1. 程式人生 > 實用技巧 >SpringBoot高階-自動配置原理剖析三

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了