Spring Boot (一): Spring Boot starter自定義

前些日子在公司接觸了spring bootspring 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.passwordstorage.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的源碼,主要是因爲工作上一直在使用這個框架。請大家繼續關注。

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