SpringBoot 自动装配
@SpringBootApplication
注解中可以看到自动装配注解@EnableAutoConfiguration
在@EnableAutoConfiguration
中可以看到@Import(AutoConfigurationImportSelector.class)
在AutoConfigurationImportSelector
的selectImports
方法中,调用了getAutoConfigurationEntry
方法
该方法会拿到需要自动装配的类名和需要排除自动装配的类名
查看getCandidateConfigurations
方法,该方法的描述为返回自动装配的类名
查看SpringFactoriesLoader.loadFactoryNames
方法
可以看到该方法从META-INF/spring.factories
获取全限定类名
查看sping-boot-autoconfigure下的spring.factories
文件
可以看到许多spring内置的自动装配类。
查看mybatis-spring-boot-autoconfigure中的spring.factories
由此可见,spring的自动装配是通过读取META-INF\spring.factories,获取自动装配类的全限定名称。
AutoConfigurationImportSelector类实现了DeferredImportSelector接口,DeferredImportSelector继承了ImportSelector接口,所以AutoConfigurationImportSelector类本质上是一个ImportSelector。
ImportSelector的描述是确定那些类可以按照@Configuration的方式处理,即将指定的类注入到Spring容器中。
ImportSelector在ConfigurationClassParser的processImports方法中被使用。
在doProcessConfigurationClass方法中,可以看到@Component,@PropertySources,@ComponentScans,@Import,@ImportResource,@Bean 注解修饰的类都会被处理,放入Map<ConfigurationClass, ConfigurationClass> configurationClasses中。
在ConfigurationClassPostProcessor中类中会调用该配置,该类实现了BeanDefinitionRegistryPostProcessor接口,方法postProcessBeanDefinitionRegistry用来注册更多的bean到spring容器中,在这期间,会获取configurationClasses中的配置,进行bean是否需要进行注册判断,@Conditional相关注解的判断也是在此方法中进行的,@ConditionalOnBean与@ConditionalOnMiss注解不生效的原因也与此处BeanDefinition的注册顺序有关
自定义Redisson Starter
新建一个maven queck-start 项目
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.6</version>
<!-- 依赖不传递 -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.4</version>
<!-- 依赖不传递 -->
<optional>true</optional>
</dependency>
创建配置类
@ConfigurationProperties(prefix = "my.redisson")
public class RedissonProperties {
private String host = "localhost";
private int port = 6379;
private String password;
private int timeout;
private boolean ssl;
// getter and setter
}
创建自动装配类
// 条件装配,存在Redisson类时才装配
@ConditionalOnClass(Redisson.class)
// 将RedissProperties注入Spring
@EnableConfigurationProperties(RedissonProperties.class)
@Configuration
public class RedissonAutoConfiguration {
@Bean
public RedissonClient redissonClient(RedissonProperties redissonProperties) {
Config config = new Config();
String prefix = "redis://";
if (redissonProperties.isSsl()) {
prefix = "rediss://";
}
config.useSingleServer().setAddress(prefix + redissonProperties.getHost() + ":" + redissonProperties.getPort())
.setPassword(redissonProperties.getPassword()).setTimeout(redissonProperties.getTimeout());
return Redisson.create(config);
}
}
创建spring.factories
在resources下创建目录META-INF,并在该目录下创建文件spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.example.RedissonAutoConfiguration
在IDEA中,拼写正确文件前会有一个spring的标识
执行 mvn install -Dmaven.test.skip=true 进行依赖打包
测试是否有自动装配
通过start.spring.io创建一个SpringBoot项目,引入之前打包的依赖
<dependency>
<groupId>org.example</groupId>
<artifactId>my-redisson-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
在application.yaml中添加自定义的配置
my:
redisson:
host: xxxxx
port: 6379
password: xxxx
timeout: 5000
将main方法改为
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(TestRedissonApplication.class, args);
System.out.println(applicationContext.getBean(RedissonAutoConfiguration.class));
}
此时启动项目,控制台会提示没有找到相关的bean,因为之前的pom中,Redisson依赖的option为true,所以需要手动将Redisson引入,这么做只是为了演示自动装配是否生效,实际使用中,自定义的start项目中redisson的依赖应没有option项
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.4</version>
</dependency>
引入之后再启动项目,此时可以发现,控制台中已经打印出了我们自定义的Starter实现类地址,说明自动装配成功了,一个自定义的start组件完成了。
增加配置文件提示
目前为止,我们自定义的starter还无法实现在配置文件中提示,这对使用者来说十分不友好。
回到我们的自定义starter项目,增加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.5.6</version>
<optional>true</optional>
</dependency>
执行 mvn clean install -Dmaven.test.skip=true,重新进行打包
打包结束之后,在target/classes/META-INF下,可以看见生成了spring-configuration-metadata.json
文件,里面就是配置类相关的配置生成,此时刷新测试项目的依赖,再去application.yaml输入配置,即可出现相关的提示。
如果想要给提示增加描述信息,需在要starter的项目中,resource/META-INF下创建additional-spring-configuration-metadata.json,然后进行编辑
在IDEA中,拼写正确文件前会有一个spring的标识
{
"properties": [
{
"name": "my.redisson.host",
"type": "java.lang.String",
"sourceType": "org.example.RedissonProperties",
"defaultValue": "localhost",
"description": "redis的连接地址"
},{
"name": "my.redisson.port",
"type": "java.lang.Integer",
"sourceType": "org.example.RedissonProperties",
"defaultValue": 6379,
"description": "redis的端口"
}
]
}
之后再次打包,可以发现spring-configuration-metadata.json
中增加了相关属性
此时再去更新测试项目依赖,即可在配置配置文件时看到对应的描述