自动配置
遵循约定大约配置的原则,在boot程序启动后,起步依赖中的一些bean对象会自动注入到ioc容器
看一下我们前面写的代码有没有达到自动配置的效果呢?
没有自动,我们写了配置类,写了@Import注解,所以并没有达到自动配置的效果。那怎么办呢?接下来我们通过翻看源码的方式来了解一下SpringBoot自动配置是怎么回事!了解完毕之后我们照葫芦画瓢就可以解决问题!
自动配置-源码分析
程序引入spring-boot-starter-web 起步依赖,启动后,会自动往ioc容器中注入DispatcherServlet
接下来我们验证一下,看它有没有自动注入DispatcherServlet
创建一个SpringBoot工程
这里没有 web起步依赖
XML
<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>
主启动
java
@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起步依赖
XML
<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自动配置原理?
希望可以帮到大家,喜欢的给冯宝宝点个关注把,蟹蟹支持!!