歡迎光臨
每天分享高質量文章

Spring Boot:自定義starter

在學習Spring Boot的過程中,接觸最多的就是starter。可以認為starter是一種服務——使得使用某個功能的開發者不需要關註各種依賴庫的處理,不需要具體的配置信息,由Spring Boot自動通過classpath路徑下的類發現需要的Bean,並織入bean。舉個例子,spring-boot-starter-jdbc這個starter的存在,使得我們只需要在BookPubApplication下用 @Autowired引入DataSource的bean就可以,Spring Boot會自動創建DataSource的實體。

這裡我們會用一個不太規範的starter展示Spring Boot的自動配置的運行原理。Spring Boot的自動配置、Command-line Runner一文中曾利用StartupRunner類在程式運行啟動後首先查詢資料庫中書的數目,現在換個需求:在系統啟動後打印各個物體的數量

How Do

  • 新建一個模塊db-count-starter,然後修改db-count-starter模塊下的pom檔案,增加對應的庫。

  1.    

  2.        org.springframework.boot

  •        spring-boot

  •        

  •    

  •    

  •        org.springframework.data

  •        spring-data-commons

  •        1.9.3.RELEASE

  •    

    • 新建包結構com/test/bookpubstarter/dbcount,然後新建DbCountRunner類,實現CommandLineRunner接口,在run方法中輸出每個物體的數量。

    1. package com.test.bookpubstarter.dbcount;

    2. import org.slf4j.Logger;

    3. import org.slf4j.LoggerFactory;

    4. import org.springframework.boot.CommandLineRunner;

    5. import org.springframework.data.repository.CrudRepository;

    6. import java.util.Collection;

    7. public class DbCountRunner implements CommandLineRunner {

    8.    protected final Logger logger = LoggerFactory.getLogger(DbCountRunner.class);

    9.    private Collection<CrudRepository> repositories;

    10.    public DbCountRunner(Collection<CrudRepository> repositories) {

    11.        this.repositories = repositories;

    12.    }

    13.    @Override

    14.    public void run(String... strings) throws Exception {

    15.        repositories.forEach(crudRepository -> {

    16.            logger.info(String.format("%s has %s entries",

    17.                    getRepositoryName(crudRepository.getClass()),

    18.                    crudRepository.count()));

    19.        });

    20.    }

    21.    private static String getRepositoryName(Class crudRepositoryClass) {

    22.        for (Class repositoryInterface : crudRepositoryClass.getInterfaces()) {

    23.            if (repositoryInterface.getName().startsWith("com.test.bookpub.repository")) {

    24.                return repositoryInterface.getSimpleName();

    25.            }

    26.        }

    27.        return "UnknownRepository";

    28.    }

    29. }

    • 增加自動配置檔案DbCountAutoConfiguration

    1. package com.test.bookpubstarter.dbcount;

    2. import org.springframework.context.annotation.Bean;

    3. import org.springframework.context.annotation.Configuration;

    4. import org.springframework.data.repository.CrudRepository;

    5. import java.util.Collection;

    6. @Configuration

    7. public class DbCountAutoConfiguration {

    8.    @Bean

    9.    public DbCountRunner dbCountRunner(Collection<CrudRepository> repositories) {

    10.        return new DbCountRunner(repositories);

    11.    }

    12. }

    • 在src/main/resources目錄下新建META-INF檔案夾,然後新建spring.factories檔案,這個檔案用於告訴Spring Boot去找指定的自動配置檔案,因此它的內容是

    1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

    2. com.test.bookpubstarter.dbcount.DbCountAutoConfiguration

    • 在之前的程式基礎上,在頂層pom檔案中增加starter的依賴

    1.   com.test

  •   db-count-starter

  •   0.0.1-SNAPSHOT

    • 把StartupRunner相關的註釋掉,然後在main函式上右鍵Run BookPubApplication.main(...),可以看出我們編寫的starter被主程式使用了。

    分析

    正規的starter是一個獨立的工程,然後在maven中新倉庫註冊發佈,其他開發人員就可以使用你的starter了。

    常見的starter會包括下麵幾個方面的內容:

    1. 自動配置檔案,根據classpath是否存在指定的類來決定是否要執行該功能的自動配置。

    2. spring.factories,非常重要,指導Spring Boot找到指定的自動配置檔案。

    3. endpoint:可以理解為一個admin,包含對服務的描述、界面、交互(業務信息的查詢)

    4. health indicator:該starter提供的服務的健康指標

    在應用程式啟動過程中,Spring Boot使用SpringFactoriesLoader類加載器查找org.springframework.boot.autoconfigure.EnableAutoConfiguration關鍵字對應的Java配置檔案。Spring Boot會遍歷在各個jar包種META-INF目錄下的spring.factories檔案,構建成一個配置檔案鏈表。除了EnableAutoConfiguration關鍵字對應的配置檔案,還有其他型別的配置檔案:

    • org.springframework.context.ApplicationContextInitializer

    • org.springframework.context.ApplicationListener

    • org.springframework.boot.SpringApplicationRunListener

    • org.springframework.boot.env.PropertySourceLoader

    • org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider

    • org.springframework.test.contex.TestExecutionListener

    Spring Boot的starter在編譯時不需要依賴Spring Boot的庫。這個例子中依賴spring boot並不是因為自動配置要用spring boot,而僅僅是因為需要實現CommandLineRunner接口。

    兩個需要註意的點

    1. @ConditionalOnMissingBean的作用是:只有對應的ban在系統中都沒有被創建,它修飾的初始化代碼塊才會執行,用戶自己手動創建的bean優先

    2. Spring Boot starter如何找到自動配置檔案(xxxxAutoConfiguration之類的檔案)?

    • spring.factories:由Spring Boot觸發探測classpath目錄下的類,進行自動配置;

    • @Enable:有時需要由starter的用戶觸發*查找自動配置檔案的過程。

    赞(0)

    分享創造快樂

    © 2021 知識星球   网站地图