SpringBoot高级-自动配置原理剖析三
前言:通过前面两篇关于自动配置原理的剖析,我们可能对自动配置有一些了解,下面我们根据源码来具体研究SpringBoot中,是如何使用自动配置的。
一、找到IDEA目录中的External Libraries
二、继续找spring-boot-autoconfigure依赖
三、继续找到autoconfigure菜单下的注解类,这些注解我们都可以在自己的程序中使用
释义:
@ConditionalOnBean:当Bean存在时,才能在IOC容器中注入Bean;
@ConditionalOnClass:当类(字节码文件)存在时,才能在IOC容器中注入Bean;(与我们前面剖析中自定义的注解功能相同)
@ConditionalOnMissingBean:当Bean不存在时,才能在IOC容器中注入Bean;
@ConditionalOnMissingClass:当类(字节码文件)不存在时,才能在IOC容器中注入Bean;
@ConditionalOnProperty:当属性存在时,才能在IOC容器中注入Bean;
@ConditionalOnResource:当资源存在时,才能在IOC容器中注入Bean;
四、查看@ConditionalOnBean源码:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnBeanCondition.class})
public @interface ConditionalOnBean {
Class<?>[] value() default {};
String[] type() default {};
Class<? extends Annotation>[] annotation() default {};
String[] name() default {};
SearchStrategy search() default SearchStrategy.ALL;
Class<?>[] parameterizedContainer() default {};
}
五、查看RedisTemplate源码,了解redis实现自动配置的原理,在下图目录中查找(凡是源码文件名称是*AutoConfiguration.class的字节码文件,都是可以自动配置的类)
六、查看源码,首先有一点需要知道,就是类上的注解与方法上的注解作用域不同,类上的注解适用于类所有的方法,比如RedisAutoConfiguration类上的@ConditionalOnClass(RedisOperations.class),而方法上的注解,只作用于该方法,比如RedisAutoConfiguration类的redisTemplate()方法上的@ConditionalOnMissingBean(name = "redisTemplate")
@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;
}
}
@ConditionalOnClass(RedisOperations.class)注解就要求,首先IOC容器中必须存在RedisOperations这个字节码文件,才会在容器启动时,自动注入其声明的Bean(使用@Bean注解的方法,Bean的名称就是方法的名称,例如上面源码中声明的 redisTemplate 与 stringRedisTemplate),然后对于redisTemplate这个Bean能否自动初始化,还需要满足注解@ConditionalOnMissingBean(name = "redisTemplate")的要求,即:IOC容器中没有一个名称为redisTemplate的Bean,这样方可在容器启动的时候,初始化redisTemplate这个Bean。同理,stringRedisTemplate这个Bean的初始化策略。
针对SpringBoot提供的条件注解示例
一、@ConditionalOnProperty注解的使用,继续使用之前的代码,稍作修改,如下:
释义:自定义一个配置类(当程序启动时,配置类会自动加载),配置类在自动加载时,如果配置文件中,有一个属性名称是name,属性值为libai的属性存在,那么会在IOC容器中,自动将user2这个Bean初始化。
/**
* @description:User配置类
* @date: 2020/10/9 15:25
* @author: winson
*/
@Configuration
public class UserConfig {
@Bean
@ConditionalOnProperty(name = "name", havingValue = "libai")
public User user2() {
return new User();
}
}
二、测试类
@SpringBootApplication
public class SpringbootConditionApplication {
public static void main(String[] args) {
//启动SpringBoot的应用,返回Spring的IOC容器
ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);
Object user2 = context.getBean("user2");
System.out.println("user2=" + user2);
}
}
三、测试结果如下,因为我现在并未在配置文件中加入相应属性
四、在配置文件中加入属性
name: libai
五、再测试,可以获取到user2这个Bean了