自动配置
遵循约定大约配置的原则,在boot程序启动后,起步依赖中的一些bean对象会自动注入到ioc容器
看一下我们前面写的代码有没有达到自动配置的效果呢?
没有自动,我们写了配置类,写了@Import注解,所以并没有达到自动配置的效果。那怎么办呢?接下来我们通过翻看源码的方式来了解一下SpringBoot自动配置是怎么回事!了解完毕之后我们照葫芦画瓢就可以解决问题!
自动配置-源码分析
程序引入spring-boot-starter-web 起步依赖,启动后,会自动往ioc容器中注入DispatcherServlet
接下来我们验证一下,看它有没有自动注入DispatcherServlet
创建一个SpringBoot工程
这里没有 web起步依赖
<dependencies>
<!--springboot核心起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
主启动
@SpringBootApplication
public class SpringbootAutoConfigApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringbootAutoConfigApplication.class, args);
System.out.println(context.getBean("dispatcherServlet"));
}
}
这时候工程里面没有 web起步依赖 就没有 DispatcherServlet,这里就会报错
导入 web起步依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
那就验证了之前的话,如果你引入了web起步依赖,就会自动往ioc容器中注入一个DispatcherServlet,那SpringBoot如何做到的呢?接下来就要翻一下源码了。
源码解读
@SpringBootApplication 注解
我们进入这个注解,它的头上怎么顶着这么多注解,不过真正重要的只有三个注解,我们接下来会 一 一介绍。
@Target(ElementType.TYPE) //元注解,可以在类上面使用 @Retention(RetentionPolicy.RUNTIME) //元注解,运行时阶段
@Documented //生成Java文档
@Inherited //是一个标识,用来修饰注解
@SpringBootConfiguration 注解
点进@SpringBootConfiguration
注解,可以发现其核心注解为@Configuration
注解:
@Configuration注解是Spring框架的注解之一,用于标记配置类。 在Spring Boot中,使用@Configuration注解可以将该类作为配置类,从而使该类中的Bean可以被Spring IoC容器管理和使用。
在配置类中,我们可以使用另外两个注解@Bean和@Scope来定义Bean,其中@Bean注解用于定义Bean对象,而@Scope注解用来指定Bean对象的作用域。
总的来说,@Configuration注解能够将一个类定义为Spring Boot应用程序中的配置类,从而使该类中的Bean对象能够被Spring IoC容器进行自动管理和装配。这让应用开发者能够更加专注于应用逻辑的实现,而不必花费精力在繁琐的配置上。 所以@SpringBootConfiguration
注解本质上就是一个@Configuration
注解,用来标注某个类为 JavaConfig 配置类,有了这个注解就可以在 SpringBoot 启动类中使用@Bean
标签配置类了。
@ComponentScan 注解
@ComponentScan 是 Spring Framework 中的一个注解,它用于指定 Spring 容器需要扫描和管理的组件。组件是 Spring 中的一个抽象概念,它包括了 Spring Bean、Controller、Service、Repository 等等。通过 @ComponentScan 注解,可以让 Spring 容器自动扫描和管理这些组件,从而简化应用程序的配置和管理。 @ComponentScan 注解有多个参数,可以用于指定要扫描的组件的位置、排除不需要扫描的组件、指定要排除扫描的组件等等。
默认情况下,Spring Boot会自动扫描主应用程序下的所有组件(@Configuration, @Controller, @Service, @Repository等),但是如果你将组件放在其他包下,那么就需要显式地配置扫描目录。
@EnableAutoConfiguration 注解
这是今天的主角中的主角,自动配置实现的核心注解。 点进这个注解可以发现,如下图所示。
我们重点来看 @Import(AutoConfigurationImportSelector.class)
这个注解。 @Import 注解是 它用于将一个或多个类导入到 Spring 容器中,以便于在应用程序中使用。通过 @Import 注解,我们可以将一些非 Spring 管理的类实例化并注册到 Spring 容器中,或者将一些 Spring 管理的配置类导入到当前配置类中,以便于在应用程序中进行统一的配置和管理。 @Import
是Spring Framework 中的一个注解,用于在配置类中导入其他配置类或者普通的Java类。
说白了在这里@Import
注解的作用就是将 AutoConfigurationImportSelector 这个类导入当前类,这个类就是实现自动配置的核心。 我们继续进入到 AutoConfigurationImportSelector 类:
AutoConfigurationImportSelector实现了DeferredImportSelector接口,我们进入DeferredImportSelector接口
最后,我们发现, AutoConfigurationImportSelector 实际上是实现了 ImportSelector 接口,这个接口只有两个方法,其中我们需要重点关注 selectImports() 方法。
ImportSelector 接口是 Spring Framework 中的一个接口,它可以用于在 Spring 容器启动时动态地导入一些类到 Spring 容器中。通过实现 ImportSelector 接口,并重写其中的 selectImports 方法,我们可以自定义逻辑来确定需要导入的类,从而实现更加灵活的配置和管理。
selectImports 方法是 ImportSelector 接口中的一个方法,用于返回需要导入的类的全限定类名数组。在 Spring 容器启动时,Spring 会扫描所有实现了 ImportSelector 接口的类,并调用其中的 selectImports 方法来确定需要导入的类。
我们进入getAutoConfigurationEntry()方法
这里返回AutoConfigurationEntry类,里面传入了 configurations和exclusions两个参数, configurations参数通过getCandidateConfigurations() 方法得到,我们进入getCandidateConfigurations()方法。
Assert.notEmpty这是一个断言,configurations不能为空 ,如果为空了,给你一段提示:没有自动配置的类找到,在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports找到,我们将这端配置简称为 .imports 文件,意思就是说,我要去找自动配置类 去 .imports中找,但是我并没有找到,我们需要关注这个配置文件在什么地方,这里先回到pom.xml文件中
进去核心起步依赖,这里面引入了一个:spring-boot-autoconfigure,autoconfigure顾名思义就是自动配置的意思。
接下来我们去找到autoconfigure
在这里我们找到了 AutoConfiguration.imports配置文件
点进去,这个配置文件其实就是配置了一堆类的全类名,这些类都是自动配置类,接下来我们去看看之前演示的DispatcherServlet相关的自动配置类 Ctrl+F:搜索一下
进入:DispatcherServletAutoConfiguration类 , Ctrl+Shift+N全局搜索进入这个类
@AutoConfiguration(after = {ServletWebServerFactoryAutoConfiguration.class})顾名思义,自动配置的意思
@AutoConfiguration点进去,你会发现它也是一个组合注解,组合了一个@Configuration()
说白了DispatcherServletAutoConfiguration这个类是一个配置类
这个类用了@AutoConfiguration注解,更加见名之意它是一个配置类
我们再看@ConditionalOnClass这个注解,是不是很熟悉,前面讲到过:它在这里的意思是,如果你环境里面有DispatcherServlet,那自动配置类就会生效自动注入一个DispatcherServlet的bean对象,如果环境里没有DispatcherServlet,那就不生效,不注入了。
接下来继续往下看
这里内部有一个DispatcherServletConfiguration类,也配置@Configuration注解,里面写一个方法,方法最终返回的就是dispatcherServlet,方法上面有@Bean注解,最终我们可以看到,它注入DispatcherServlet的代码在这里,其实你会发现这里的代码和我们之前写的代码并没有很大的区别,都是写一个方法,让后在方法上面声明一个@Bean注解。
这里最核心的是,它把这个类DispatcherServletAutoConfiguration写到指定的配置文件里面了,那么SpringBoot就可以自动的去读取这个全类名,把这个配置的类的对象注入到Ioc容器中,由于这个配置类的内部还有配置类DispatcherServletConfiguration,内部的配置类里面还有一些方法,这些方法声明了@Bean注解,所以SpringBoot它会继续解析,直到把这些@Bean注解的方法都解析到,执行这些方法,然后把返回值注入到IOC容器里。
因此我们自动配置的核心在哪?核心核心,在这个.imports配置文件中,那么源码我们就到这。
小总结
在SpringBoot2.7版本以前,它自动配置使用的配置文件是 spring.factories,它会从 spring.factories配置文件中读取配置类的全类名,那么在SpringBoot2.7以后到3.0以前,它同时兼容了.imports配置文件以及spring.factories配置文件,在3.0以后只支持.imports配置文件,这个大家要清楚。
通过源码分析,我们知道了,SpringBoot自动配置无非就是提供一个自动配置类,把这个类名写到指定的配置文件中就可以了。
说一说SpringBoot自动配置原理?
希望可以帮到大家,喜欢的给冯宝宝点个关注把,蟹蟹支持!!