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了