前些日子在公司接觸了spring boot
和spring cloud
,有感於其大大簡化了spring的配置過程,十分方便使用者快速構建項目,而且擁有豐富的starter供開發者使用。但是由於其自動化配置的原因,往往導致出現問題,新手無法快速定位問題。這裏我就來總結一下spring boot 自定義starter的過程,相信大家看完這篇文章之後,能夠對spring boot starter
的運行原理有了基本的認識。
爲了節約你的時間,本篇文章的主要內容有:
- spring boot starter的自定義
- spring boot auto-configuration的兩種方式,spring.factories和註解
- Conditional註解的使用
引入pom依賴
相信接觸過spring boot的開發者都會被其豐富的starter所吸引,如果你想給項目添加redis支持,你就可以直接引用spring-boot-starter-redis
,如果你想使項目微服務化,你可以直接使用spring-cloud-starter-eureka
。這些都是spring boot所提供的便利開發者的組件,大家也可以自定義自己的starter並開源出去供開發者使用。
創建自己的starter項目需要maven依賴是如下所示:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
核心配置類StorageAutoConfigure
構建starter的關鍵是編寫一個裝配類,這個類可以提供該starter核心bean。這裏我們的starter提供一個類似redis
的鍵值存儲功能的bean,我們叫它爲StorageService
。負責對這個bean進行自動化裝配的類叫做StorageAutoConfigure
。保存application.properties配置信息的類叫做StorageServiceProperties
。這三種類像是鐵三角一樣,你可以在很多的spring-boot-starter
中看到他們的身影。
我們首先來看StorageAutoConfigure
的定義。
@Configuration
@ConditionalOnClass(StorageService.class)
@EnableConfigurationProperties(StorageServiceProperties.class)
public class StorageAutoConfigure {
@Autowired
private StorageServiceProperties properties;
@Bean
@ConditionalOnMissingBean(StorageService.class)
@ConditionalOnProperty(prefix = "storage.service", value = "enabled", havingValue = "true")
StorageService exampleService() {
return new StorageService(properties);
}
}
我們首先講一下源碼中註解的作用。
-
@Configuration
,被該註解註釋的類會提供一個或則多個@bean
修飾的方法並且會被spring容器處理來生成bean definitions
。 -
@bean
註解是必須修飾函數的,該函數可以提供一個bean
。而且該函數的函數名必須和bean的名稱一致,除了首字母不需要大寫。 -
@ConditionalOnClass
註解是條件判斷的註解,表示對應的類在classpath目錄下存在時,纔會去解析對應的配置文件。 -
@EnableConfigurationProperties
註解給出了該配置類所需要的配置信息類,也就是StorageServiceProperties
類,這樣spring容器纔會去讀取配置信息到StorageServiceProperties
對象中。 -
@ConditionalOnMissingBean
註解也是條件判斷的註解,表示如果不存在對應的bean條件才成立,這裏就表示如果已經有StorageService
的bean了,那麼就不再進行該bean的生成。這個註解十分重要,涉及到默認配置和用戶自定義配置的原理。也就是說用戶可以自定義一個StorageService
的bean,這樣的話,spring容器就不需要再初始化這個默認的bean了。 -
ConditionalOnProperty
註解是條件判斷的註解,表示如果配置文件中的響應配置項數值爲true,纔會對該bean進行初始化。
看到這裏,大家大概都明白了StorageAutoConfigure
的作用了吧,spring容器會讀取相應的配置信息到StorageServiceProperties
中,然後依據調節判斷初始化StorageService這個bean。集成了該starter
的項目就可以直接使用StorageService
來存儲鍵值信息了。
配置信息類StorageServiceProperties
存儲配置信息的類StorageServiceProperties
很簡單,源碼如下所示:
@ConfigurationProperties("storage.service")
public class StorageServiceProperties {
private String username;
private String password;
private String url;
......
//一系列的getter和setter函數
}
@ConfigurationProperties
註解就是讓spring容器知道該配置類的配置項前綴是什麼,上述的源碼給出的配置信息項有storage.service.username
,storage.service.password
和storage.service.url
,類似於數據庫的host和用戶名密碼。這些配置信息都會由spring容器從application.properties
文件中讀取出來設置到該類中。
starter提供功能的StorageService
StorageService
類是提供整個starter的核心功能的類,也就是提供鍵值存儲的功能。
public class StorageService {
private Logger logger = LoggerFactory.getLogger(StorageService.class);
private String url;
private String username;
private String password;
private HashMap<String, Object> storage = new HashMap<String, Object>();
public StorageService(StorageServiceProperties properties) {
super();
this.url = properties.getUrl();
this.username = properties.getUsername();
this.password = properties.getPassword();
logger.debug("init storage with url " + url + " name: " + username + " password: " + password);
}
public void put(String key, Object val) {
storage.put(key, val);
}
public Object get(String key) {
return storage.get(key);
}
}
註解配置和spring.factories
自定義的starter
有兩種方式來通知spring容器導入自己的auto-configuration類,也就是本文當中的StorageAutoConfigure
類。
一般都是在starter
項目的resources/META-INF
文件夾下的spring.factories文件中加入需要自動化配置類的全限定名稱。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=starter.StorageAutoConfigure
spring boot
項目中的EnableAutoConfigurationImportSelector
會自動去每個jar的相應文件下查看spring.factories文件內容,並將其中的類加載出來在auto-configuration過程中進行配置。而EnableAutoConfigurationImportSelector
在@EnableAutoConfiguration
註解中被import
。
第一種方法只要是引入該starter,那麼spring.factories中的auto-configuration類就會被裝載,但是如果你希望有更加靈活的方式,那麼就使用自定義註解來引入裝配類。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(StorageAutoConfigure.class)
@Documented
public @interface EnableStorage {
}
有了這個註解,你可以在你引入該starter的項目中使用該註解,通過@import
註解,spring容器會自動加載StorageAutoConfigure
並自動化進行配置。
後記
上述只是關於spring boot starter最爲簡單的定製和原理分析,後續我準備研究一下spring cloud stream
的源碼,主要是因爲工作上一直在使用這個框架。請大家繼續關注。