以spring-boot-starter-data-redis为例:
查看spring-boot-autoconfigure包中的META-INF/spring.factories:
可以发现 其中的org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的value中已经包含了RedisAutoConfiguration。
RedisAutoConfiguration类也是在spring-boot-autoconfigure包中的,spring-boot-autoconfiguration包把常用的插件的starter依赖的配置类都放了进来。
RedisAutoConfiguration类中:
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
@Bean:创建了两个Bean,第一个是根据注入的RedisConnectionFactory对象生成RedisTemplate对象,就是我们平时使用的RedisTemplate对象;第二个是根据注入的RedisConnectionFactory对象生成StringRedisTemplate对象。
@Configuration:表示它是一个配置类;
@EnableConfigurationProperties(RedisProperties.class):引入RedisProperties类中的配置,而RedisProperties.class类标识了@ConfigurationProperties(prefix="spring.redis"),说明了它会读取application.properties文件中以spring.redis为前缀的所有配置,并引入自己的成员变量中,成员变量有默认值,也就是对应的配置有默认值;
@Import({LettuceConnectionConfiguration.class,JedisConnectionConfiguration.class}):引入两个配置类,我们以JedisConnectionConfiguration.class为例进行说明:
JedisConnectionConfiguration类中:
@Configuration
@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
class JedisConnectionConfiguration extends RedisConnectionConfiguration {
private final RedisProperties properties;
private final ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers;
JedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
ObjectProvider<RedisClusterConfiguration> clusterConfiguration,
ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
super(properties, sentinelConfiguration, clusterConfiguration);
this.properties = properties;
this.builderCustomizers = builderCustomizers;
}
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public JedisConnectionFactory redisConnectionFactory() throws UnknownHostException {
return createJedisConnectionFactory();
}
...省略部分代码
看到了吧,我们上面创建RedisTemplate对象所需要依赖的RedisConnectionFactory对象在这里面创建的,这里面创建的Bean: JedisConnectionFactory是RedisConnectionFactory的子类。
在构造函数中,把前面引入的RedisProperties作为了参数。整个类配置类的作用就是根据RedisProperties中的配置来创建了一个JedisConnectionFactory对象。
但是这个配置类发挥作用是由前提的:必须包含@ConditionalOnClass中声明的类。其中JedisConnection.class在spring-data-redis包中,而Jedis.class在jedis包中,但JedisConnectionConfiguration配置类还是在spring-boot-autoconfiguration包中。如果你的pom依赖中没有spring-data-redis或jedis,那么@ConditionalOnClass中声明的类是会报红的,但是不会影响编译!SpringBoot可以根据@ConditionalOnClass选择性的进行加载,从而避免编译时报错,具体见代码:ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(),ConditionEvaluator.shouldskip()
总结:
在spring.factories中找到EnableAutoConfiguration对应的配置类;在具体的配置类中,引入@ConfigurationProperties类,这个类里面的成员变量对应了properties中的配置项;如果有依赖的Bean在其他包中,声明在@ConditionalOnClass中。然后再这个配置类中装配出最终变成需要的Bean即可。
很简单,不是么。现在你知道为什么简单地引入pom依赖包,简单地配置以下properties,就可以正常使用RedisTemplate类的原因了吧。
自己创建一个starter:
一般spring-boot-starter-xxx.jar包是官方已有的,不需要自己做,自己做的starter需要命名为xxx-spring-boot-starter。
1.创建META-INF/spring.factories文件,编辑好:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxx.xxx.xxx.MyAutoConfiguration
1、创建动态属性配置类MyProperties,标注@ConfigurationProperties, 与application.properties中的属性相对应;
2、写好MyAutoConfiguration配置类,通过@EnableConfigurationProperties引入MyProperties;
3、在当前项目的resources目录下新建 META-INF/spring.factories 文件里面内容如下: org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxx.xxx.xxx.MyAutoConfiguration
将写好的spring-boot-starter-xxx.jar包引入,就可以直接使用里面自动装配好的Bean了。