Spring Boot四大神器之建立自定義Starter

weixin_33766168發表於2019-02-27

1. 概述

Spring Boot為開發人員提供了大多數流行的開源專案的啟動器,但我們不僅限於此。

我們也可以編寫自己的自定義啟動器。 如果想為我們的組織提供一個內部庫,並且將它在Spring Boot上下文中使用,那麼為它編寫一個啟動器也許是一個好的習慣。

這些啟動器使開發人員能夠避免冗長的配置並快速啟動他們的開發。但是,由於隱藏了在後臺發生的很多事情,有時候很難理解註釋或只是在pom.xml中包含些依賴項就能夠實現這麼多功能。

在本文中,我們將揭開Spring Boot的神祕面紗,看看幕後發生了什麼。然後我們將使用這些概念為我們自己的自定義庫建立一個啟動器。

2. 揭開Spring Boot自動配置的神祕面紗

2.1 自動配置類

當Spring Boot啟動時,它會在類路徑中查詢名為spring.factories的檔案。該檔案位於META-INF目錄中。讓我們看一下spring-boot-autoconfigure專案中這個檔案的片段:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

此檔案將名稱對映到Spring Boot將嘗試執行的不同配置類。因此,根據這個片段,Spring Boot將嘗試執行RabbitMQ,Cassandra,MongoDB和Hibernate的所有配置類。

這些類是否實際執行將取決於類路徑上是否存在依賴類。例如,如果在類路徑中找到MongoDB的類,則將執行MongoAutoConfiguration,並初始化所有與mongo相關的bean。

此條件初始化由@ConditionalOnClass註釋啟用。讓我們看一下MongoAutoConfiguration類的程式碼片段,看看它的用法:

@Configuration
@ConditionalOnClass(MongoClient.class)
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
public class MongoAutoConfiguration {
    // configuration code
}

現在如果MongoClient在類路徑中可用 - 這個配置類將執行,使用預設配置設定初始化的MongoClient來填充Spring bean工廠。

2.2 application.properties檔案中的自定義屬性

Spring Boot使用一些預先配置的預設值初始化bean。要覆蓋這些預設值,我們通常會在application.properties檔案中使用某個特定名稱宣告它們。Spring Boot容器會自動獲取這些屬性。

讓我們看看它是如何工作的。

在MongoAutoConfiguration的程式碼片段中,使用MongoProperties類宣告@EnableConfigurationProperties註釋,該類充當自定義屬性的容器:

@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {
 
    private String host;
 
    // other fields with standard getters and setters
}

字首加上欄位名稱可以在application.properties檔案中建立屬性的名稱。因此,要設定MongoDB 的主機,我們只需要在屬性檔案中編寫以下內容:

spring.data.mongodb.host = localhost

同樣,可以使用屬性檔案設定類中其他欄位的值。

3. 建立自定義啟動器

根據第2節中的概念,要建立自定義啟動器,我們需要編寫以下元件:

  • 我們庫的自動配置類以及自定義配置的屬性類。
  • 一個啟動程式pom,用於引入庫和autoconfigure專案的依賴項。

為了演示,我們建立了一個簡單的greeter庫,它將作為配置引數接收一天中不同時間的問候訊息並輸出問候應答訊息。我們還將建立一個示例Spring Boot應用程式來演示我們的autoconfigure和starter模組的用法。

3.1 自動配置模組

我們將自動配置模組稱為greeter-spring-boot-autoconfigure。該模組將有兩個主要類,即GreeterProperties - 它將通過application.properties檔案和GreeterAutoConfiguartion設定自定義屬性,這將為greeter庫建立bean 。

讓我們看看這兩個類的程式碼:

@ConfigurationProperties(prefix = "peterwanghao.samples.greeter")
public class GreeterProperties {
 
    private String userName;
    private String morningMessage;
    private String afternoonMessage;
    private String eveningMessage;
    private String nightMessage;
 
    // standard getters and setters
 
}
@Configuration
@ConditionalOnClass(Greeter.class)
@EnableConfigurationProperties(GreeterProperties.class)
public class GreeterAutoConfiguration {
 
    @Autowired
    private GreeterProperties greeterProperties;
 
    @Bean
    @ConditionalOnMissingBean
    public GreetingConfig greeterConfig() {
 
        String userName = greeterProperties.getUserName() == null
          ? System.getProperty("user.name") 
          : greeterProperties.getUserName();
         
        // ..
 
        GreetingConfig greetingConfig = new GreetingConfig();
        greetingConfig.put(USER_NAME, userName);
        // ...
        return greetingConfig;
    }
 
    @Bean
    @ConditionalOnMissingBean
    public Greeter greeter(GreetingConfig greetingConfig) {
        return new Greeter(greetingConfig);
    }
}

我們還需要在src/main/resources/META-INF目錄中新增一個spring.factories檔案,其中包含以下內容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.peterwanghao.samples.greeter.autoconfigure.GreeterAutoConfiguration

在應用程式啟動時,如果類路徑中存在類Greeter,則將執行GreeterAutoConfiguration類。如果成功執行,它將通過GreeterProperties類讀取屬性,使用GreeterConfig和Greeter bean 填充Spring應用程式上下文。

@ConditionalOnMissingBean註釋將確保,如果他們不存在,這些bean才會建立。這使開發人員可以通過在其中一個@Configuration類中定義自己配置的bean來完全覆蓋自動配置的bean 。

3.2 建立pom.xml

現在讓我們建立一個啟動程式pom,它將為自動配置模組和greeter庫帶來依賴關係。

根據命名約定,所有不由核心Spring Boot團隊管理的啟動器應該以庫名稱開頭,後面跟字尾-spring-boot-starter。所以我們將把我們的啟動器稱為greeter-spring-boot-starter:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.peterwanghao.samples.springboot</groupId>
    <artifactId>spring-boot-custom-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>greeter-spring-boot-starter</artifactId>
  <name>greeter-spring-boot-starter</name>
  
  <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

        <dependency>
            <groupId>com.peterwanghao.samples.springboot</groupId>
            <artifactId>greeter-spring-boot-autoconfigure</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>com.peterwanghao.samples.springboot</groupId>
            <artifactId>greeter-library</artifactId>
            <version>${greeter.version}</version>
        </dependency>

    </dependencies>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <greeter.version>0.0.1-SNAPSHOT</greeter.version>
        <spring-boot.version>2.1.1.RELEASE</spring-boot.version>
    </properties>
</project>

3.3 使用Starter

讓我們建立一個使用啟動器的應用greeter-spring-boot-sample-app。在pom.xml中,我們需要將其新增為依賴項:

<dependency>
    <groupId>com.peterwanghao.samples.springboot</groupId>
    <artifactId>greeter-spring-boot-starter</artifactId>
    <version>${greeter-starter.version}</version>
</dependency>

Spring Boot將自動配置所有內容,我們將準備好注入和使用Greeter bean。

讓我們通過使用peterwanghao.samples.greeter字首在application.properties檔案中定義GreeterProperties的一些屬性值來改變它們的一些預設值:

peterwanghao.samples.greeter.userName=Peter
peterwanghao.samples.greeter.afternoonMessage=Woha\Afternoon

最後,讓我們在我們的應用程式中使用Greeter bean:

@SpringBootApplication
public class GreeterSampleApplication implements CommandLineRunner {
 
    @Autowired
    private Greeter greeter;
 
    public static void main(String[] args) {
        SpringApplication.run(GreeterSampleApplication.class, args);
    }
 
    public void run(String... args) throws Exception {
        String message = greeter.greet();
        System.out.println(message);
    }
}

4. 結論

在這個簡單教程中,我們專注於建立自定義Spring Boot啟動器,以及這些啟動器如何與自動配置機制一起工作 - 通過後臺工作以消除大量手動配置。

我們在本文中建立的完整原始碼都可以在GitHub上找到。

相關文章