一,springboot 自动配置原理
先说说我们自己的应用程序中Bean加入容器的办法:
@SpringBootApplication
public class DemoAppApplication {
public static void main(String[] args) {
SpringApplication.run(DemoAppApplication.class, args);
}
}
我们在应用程序的入口设置了 @SpringBootApplication标签,默认情况下他会扫描所有次级目录。
如果增加了 scanBasePackages属性,就会扫描所有被指定的路径及其次级目录。
那么它在扫描的是什么东西呢?
是这个:@Component
所有被扫描到的 @Component,都会成为一个默认的singleton(单例,即一个容器里只有一个对象实体)加入到容器中。
认识到以上这点,便于我们理解springboot自动配置的机制。
接下来让我们看看在自己的应用程序中实现配置的方法。
@Configuration
public class RestTemplateConfig {
public RestTemplateConfig(){
System.out.println("初始化redis配置");
}
}
这里我们设置了一个配置,往容器中加入了一个RestTemplateConfig
首先说 @Configuration,这个标签继承了 @Component标签,我们可以在标签内容看到:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
可以看到其中是有 @Component标签的,所以,@Configuration会被 @SpringBootApplication扫描到,进而把它和它下面的 @Bean加入容器,于是我们RestTemplateConfig 的内容就配置完成了,在后续的使用中,我们就可以直接从容器中拿出并使用它。
二,spring.factories文件的作用
对于在maven中引用的其他外部包加入容器的过程,需要用到spring.factories。
我们创建另外一个maven工程
public class SpringUtils {
public SpringUtils(){
System.out.println("初始化SpringUtils配置");
}
}
@Configuration
public class SpringUtils2 {
public SpringUtils2(){
System.out.println("初始化SpringUtils2配置");
}
}
@Configuration
public class SpringUtils3 {
public SpringUtils3(){
System.out.println("初始化SpringUtils3配置");
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.hbcs.config.SpringUtils
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>demo2</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.2</version>
</dependency>
</dependencies>
</project>
然后使用maven install命令将该工程打包成jar,上传至本地仓库
我们在第一个项目中引入maven
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>demo2</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
启动项目,可以看到成功注入的bean
RestTemplateConfig在本项目启动类的次级目录所以被扫描到
SpringUtils通过配置spring.factories也自动加载到容器里
SpringUtils2虽然在外部工程而且没有使用spring.factories,但是由于所在路径一致,而且有注解,则同样以扫描的方式被注入
三、spring.factories自动配置原理
在springboot运行时,SpringFactoriesLoader 类会去寻找
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
SpringFactoriesLoader为什么要读取它呢?因为它内部是这样的
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.hbcs.config.SpringUtils
spring.factories用键值对的方式记录了所有需要加入容器的类,EnableAutoConfigurationImportSelector的selectImports方法返回的类名,来自spring.factories文件内的配置信息,这些配置信息的key等于EnableAutoConfiguration,因为spring boot应用启动时使用了EnableAutoConfiguration注解,所以EnableAutoConfiguration注解通过import注解将EnableAutoConfigurationImportSelector类实例化,并且将其selectImports方法返回的类名实例化后注册到spring容器。
以上内容是springboot获得这些类的方式,如果你想要实现自己的自动配置,就将你的类通过键值对的方式写在你的spring.factories即可,注意,值是你的自动配置类,键必须是org.springframework.boot.autoconfigure.EnableAutoConfiguration