1. 概述
Spring Boot為開發(fā)人員提供了大多數(shù)流行的開源項(xiàng)目的啟動(dòng)器,但我們不僅限于此。
我們也可以編寫自己的自定義啟動(dòng)器。 如果想為我們的組織提供一個(gè)內(nèi)部庫,并且將它在Spring Boot上下文中使用,那么為它編寫一個(gè)啟動(dòng)器也許是一個(gè)好的習(xí)慣。
這些啟動(dòng)器使開發(fā)人員能夠避免冗長的配置并快速啟動(dòng)他們的開發(fā)。但是,由于隱藏了在后臺發(fā)生的很多事情,有時(shí)候很難理解注釋或只是在pom.xml中包含些依賴項(xiàng)就能夠?qū)崿F(xiàn)這么多功能。
在本文中,我們將揭開Spring Boot的神秘面紗,看看幕后發(fā)生了什么。然后我們將使用這些概念為我們自己的自定義庫創(chuàng)建一個(gè)啟動(dòng)器。
2. 揭開Spring Boot自動(dòng)配置的神秘面紗
2.1 自動(dòng)配置類
當(dāng)Spring Boot啟動(dòng)時(shí),它會(huì)在類路徑中查找名為spring.factories的文件。該文件位于META-INF目錄中。讓我們看一下spring-boot-autoconfigure項(xiàng)目中這個(gè)文件的片段:
# 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將嘗試運(yùn)行的不同配置類。因此,根據(jù)這個(gè)片段,Spring Boot將嘗試運(yùn)行RabbitMQ,Cassandra,MongoDB和Hibernate的所有配置類。
這些類是否實(shí)際運(yùn)行將取決于類路徑上是否存在依賴類。例如,如果在類路徑中找到MongoDB的類,則將運(yùn)行MongoAutoConfiguration,并初始化所有與mongo相關(guān)的bean。
此條件初始化由@ConditionalOnClass注釋啟用。讓我們看一下MongoAutoConfiguration類的代碼片段,看看它的用法:
@Configuration
@ConditionalOnClass(MongoClient.class)
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
public class MongoAutoConfiguration {
// configuration code
}
現(xiàn)在如果MongoClient在類路徑中可用 - 這個(gè)配置類將運(yùn)行,使用默認(rèn)配置設(shè)置初始化的MongoClient來填充Spring bean工廠。
2.2 application.properties文件中的自定義屬性
Spring Boot使用一些預(yù)先配置的默認(rèn)值初始化bean。要覆蓋這些默認(rèn)值,我們通常會(huì)在application.properties文件中使用某個(gè)特定名稱聲明它們。Spring Boot容器會(huì)自動(dòng)獲取這些屬性。
讓我們看看它是如何工作的。
在MongoAutoConfiguration的代碼片段中,使用MongoProperties類聲明@EnableConfigurationProperties注釋,該類充當(dāng)自定義屬性的容器:
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {
private String host;
// other fields with standard getters and setters
}
前綴加上字段名稱可以在application.properties文件中創(chuàng)建屬性的名稱。因此,要設(shè)置MongoDB 的主機(jī),我們只需要在屬性文件中編寫以下內(nèi)容:
spring.data.mongodb.host = localhost
同樣,可以使用屬性文件設(shè)置類中其他字段的值。
3. 創(chuàng)建自定義啟動(dòng)器
根據(jù)第2節(jié)中的概念,要?jiǎng)?chuàng)建自定義啟動(dòng)器,我們需要編寫以下組件:
- 我們庫的自動(dòng)配置類以及自定義配置的屬性類。
- 一個(gè)啟動(dòng)程序pom,用于引入庫和autoconfigure項(xiàng)目的依賴項(xiàng)。
為了演示,我們創(chuàng)建了一個(gè)簡單的greeter庫,它將作為配置參數(shù)接收一天中不同時(shí)間的問候消息并輸出問候應(yīng)答消息。我們還將創(chuàng)建一個(gè)示例Spring Boot應(yīng)用程序來演示我們的autoconfigure和starter模塊的用法。
3.1 自動(dòng)配置模塊
我們將自動(dòng)配置模塊稱為greeter-spring-boot-autoconfigure。該模塊將有兩個(gè)主要類,即GreeterProperties - 它將通過application.properties文件和GreeterAutoConfiguartion設(shè)置自定義屬性,這將為greeter庫創(chuàng)建bean 。
讓我們看看這兩個(gè)類的代碼:
@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目錄中添加一個(gè)spring.factories文件,其中包含以下內(nèi)容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.peterwanghao.samples.greeter.autoconfigure.GreeterAutoConfiguration
在應(yīng)用程序啟動(dòng)時(shí),如果類路徑中存在類Greeter,則將運(yùn)行GreeterAutoConfiguration類。如果成功運(yùn)行,它將通過GreeterProperties類讀取屬性,使用GreeterConfig和Greeter bean 填充Spring應(yīng)用程序上下文。
@ConditionalOnMissingBean注釋將確保,如果他們不存在,這些bean才會(huì)創(chuàng)建。這使開發(fā)人員可以通過在其中一個(gè)@Configuration類中定義自己配置的bean來完全覆蓋自動(dòng)配置的bean 。
3.2 創(chuàng)建pom.xml
現(xiàn)在讓我們創(chuàng)建一個(gè)啟動(dòng)程序pom,它將為自動(dòng)配置模塊和greeter庫帶來依賴關(guān)系。
根據(jù)命名約定,所有不由核心Spring Boot團(tuán)隊(duì)管理的啟動(dòng)器應(yīng)該以庫名稱開頭,后面跟后綴-spring-boot-starter。所以我們將把我們的啟動(dòng)器稱為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
讓我們創(chuàng)建一個(gè)使用啟動(dòng)器的應(yīng)用greeter-spring-boot-sample-app。在pom.xml中,我們需要將其添加為依賴項(xiàng):
<dependency>
<groupId>com.peterwanghao.samples.springboot</groupId>
<artifactId>greeter-spring-boot-starter</artifactId>
<version>${greeter-starter.version}</version>
</dependency>
Spring Boot將自動(dòng)配置所有內(nèi)容,我們將準(zhǔn)備好注入和使用Greeter bean。
讓我們通過使用peterwanghao.samples.greeter前綴在application.properties文件中定義GreeterProperties的一些屬性值來改變它們的一些默認(rèn)值:
peterwanghao.samples.greeter.userName=Peter
peterwanghao.samples.greeter.afternoonMessage=Woha\Afternoon
最后,讓我們在我們的應(yīng)用程序中使用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. 結(jié)論
在這個(gè)簡單教程中,我們專注于創(chuàng)建自定義Spring Boot啟動(dòng)器,以及這些啟動(dòng)器如何與自動(dòng)配置機(jī)制一起工作 - 通過后臺工作以消除大量手動(dòng)配置。
我們在本文中創(chuàng)建的完整源代碼都可以在GitHub上找到。