從args講到springboot全套配置體系架構(五)

五、springboot中第三方組件如何實現自動配置

我們知道springboot 只需要引入一個starter就可以完成一個組件的集成,那麼這個starter到底是怎麼做的呢?

spring-boot-autoconfigure-2.1.9.RELEASE.jar

我們先來看看spring-boot-autoconfigure-2.1.9.RELEASE.jar 這個包。顧名思義就是springboot 自動配置的核心包。
此包下集合了我們常用的一些組件的配置類,如redis,mq,jdbc,cach等等。我們就以redis爲例展開講解
redis的配置類路徑爲此包下\org\springframework\boot\autoconfigure\data\redis
在這裏插入圖片描述
我們先來看看
RedisProperties.java 這個類

RedisProperties

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

我們發現這裏除了一個@ConfigurationProperties(prefix = “spring.redis”) 註解以外,不存在多餘的註解了,並且我們可以通過實驗可以知道這個註解的並不會被spring自動實例化。那麼爲什麼我引入redis的依賴後

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

它就會被實例化加載了呢?

@EnableConfigurationProperties註解

我們先來看看RedisAutoConfiguration這個類,redis的自動配置類
以下爲此類全部內容

@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;
	}

}

先關注這個註解@EnableConfigurationProperties(RedisProperties.class)
我們知道使用 @component系列(@Configuration…) + @ConfigurationProperties(prefix = “spring.redis”)能夠將 application + bootstrap 默認配置文件的信息導入配置類。現在這裏似乎又出現了一個可以有這種能力的註解。我們先來實驗下
新建配置類
RedisConfig.java

@Data
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfig {
    private String host;
    private String password;
    private int port;
    private int database;
}

application.properties文件添加

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456789
spring.redis.database=0

我們在測試類上添加@EnableConfigurationProperties(RedisConfig.class)這個註解

@SpringBootTest(classes = {ServiceUserApplication.class})
@RunWith(SpringRunner.class)
@EnableConfigurationProperties(RedisConfig.class)
public class ServiceUserApplicationTests {
    @Autowired
    RedisConfig redisConfig;

    @Test
    public void contextLoads() {
        System.out.println(redisConfig.getHost());
    }

}

我們很神奇的發現控制檯輸出了127.0.0.1 說明這個配置被取到了,說明RedisConfig 被實例化了。也就意味
@EnableConfigurationProperties(RedisConfig.class) 這個註解是另一個系列的Component 註解。它同樣能實例化一個bean。
假如我們把@ConfigurationProperties(prefix = “spring.redis”) 這個註解移除掉會發生什麼事情呢?

一點都不意外報瞭如下錯誤信息

Caused by: java.lang.IllegalArgumentException: No ConfigurationProperties annotation found on  'com.yzj.learn.user.config.RedisConfig'.
	at org.springframework.util.Assert.notNull(Assert.java:215)

也就是說@EnableConfigurationProperties(RedisConfig.class)這個註解引入的類名一定需要被@ConfigurationProperties(prefix = “spring.redis”) 這個註解修飾。

我們跟進@EnableConfigurationProperties發現它是被這個註解修飾的@Import(EnableConfigurationPropertiesImportSelector.class) ;我們先不管@import是幹什麼的,我們先看看他的這個入參
EnableConfigurationPropertiesImportSelector.class
這個類就是去解析了EnableConfigurationProperties 這個註解,並且通過這個註解又拿到了對應的ConfigurationProperties 註解的類的實例。然後將之實例化。

@Import 註解簡述

在回過頭看看@Import這個註解

@Import(EnableConfigurationPropertiesImportSelector.class) 這個註解實際上相當於實例化EnableConfigurationPropertiesImportSelector

那麼有人會說了那既然效果都和@Component系列註解一樣,爲啥又要分這麼多類型呢?
我來解釋下:
首先類如果被註解了@Component 系列,那麼只要它在spring的掃包路徑下,它就一定會被實例化成bean。那麼這個時候,我如果實際上並沒有使用這個實例。那麼這就造成極大的性能和資源上的浪費,而@Import +@Enable**註解的出現給加載提供了一個開關,實現按需加載。
後續還會講到一套@Condition註解,@import和@condition也就是springboot的整個核心所在。

整個springboot配置核心概念@Import +@Enable** 實現手動按需加載 @import和@condition 實現自動按需加載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章