Springboot
中的自動配置確實方便,減小了咱們開發上的複雜性,那麼自動配置原理是什麼呢?以前我也寫過了一篇文章進行了分析。
Springboot 系列(三)Spring Boot 自動配置。php
因爲自動配置用到了配置文件的綁定,若是你還不知道常見的配置文件的用法,能夠參考這篇文章。
Springboot 系列(二)Spring Boot 配置文件。java
在這一次,經過學習 Springboot
自動配置模式,編寫一個本身的 starter
,用來加深對自動配置的理解。git
熟悉模式,有助於提高編寫的 starter
的規範性,編寫本身的 starter
以前先來學習 Springboot
官方 starter
以及常見框架的整合 starter
的編寫方式 ,能夠領略到其中的奧祕。github
選擇一個官方的自動配置進行分析,這裏就選擇常見的配置端口號配置。web
使用端口號以前咱們須要先引入 web 依賴。面試
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
複製代碼
若是你觀察 starter
多的話,也許你發已經發現了一個模式,Springboot
官方的 starter
的名字都是 spring-boot-starter-xxxx
命名的。spring
查看 spring-boot-starter-web
會發現,其實這個依賴只是一個空盒子,除了依賴其餘 pom
以外,沒有一行代碼。數據庫
這時,發現了另一個模式:starter
只依賴其餘 pom
,不作代碼實現。apache
那麼 spring-boot-starter-web
到底依賴了哪些內容?springboot
觀察這個依賴信息,而後再參照其餘的官方 starter
,能夠找到幾個固定的引入,能夠被稱之爲模式的依賴引入。
spring-boot-starter
。spring-boot-autoconfigure
。引入依賴只有配置端口號,像這樣。
server.port=8090
複製代碼
IDEA 中能夠經過點擊 server.port
找到這個配置綁定的類文件。能夠看到配置最終會注入到類ServerProperties
類的 port
屬性上。
那麼這個 ServerProperties
究竟是哪裏使用的呢?繼續查找,找到一個和 Servlet
的有關的調用。
發現是被 ServletWebServerFactoryCustomizer
類進行了調用,這個類裏面定義了
private final ServerProperties serverProperties;
複製代碼
用來使用配置的屬性。
繼續查看這個類的調用,發現只有一個類使用這個類,這個類是ServletWebServerFactoryAutoConfiguration
。
根據咱們對註解的理解,這個類就是自動配置主要類了。同時自動配置類都是以 AutoConfiguration
結尾。
看這個類的幾個註解的意思。
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
複製代碼
ServletRequest
類存在和是 Web 應用時生效。@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
複製代碼
ServerProperties
的配置綁定。@EnableConfigurationProperties(ServerProperties.class)
複製代碼
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
複製代碼
同時注入配置到 Bean 工廠以供其餘地方調用。
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
複製代碼
自動配置僅僅是這些東西嗎?根據以前文章裏的分析,咱們知道不止代碼,至少還有一個指定自動配置類的配置文件須要讀取。也就是 spring.factories
文件。
若是你不知道,能夠先看這篇文章。Springboot 系列(三)Spring Boot 自動配置 。
事實確實如此,能夠在 spring.factories
中找到上面跟蹤到的類。 也就是 ServletWebServerFactoryAutoConfiguration
.
根據上面的分析,能夠發現 Springboot
官方 starter
的幾個模式。
XXXProperties
自動綁定 XXX
開頭的配置信息,如:ServerProperties
。XXXProperties
定義到要使用的類中,如:ServletWebServerFactoryCustomizer
。XXXAutoConfiguration
,開啓 XXXProperties
的自動配置,限定生效場景,建立須要的類到 Bean
工廠。如:ServletWebServerFactoryAutoConfiguration
。Springboot
官方若是把全部的框架都編寫成 starter
,是不現實的。所以不少第三方框架須要主動集成到 springboot
,因此咱們選擇一個經常使用的框架分析它的 starter
實現。由於已經看過了 springboot
官方 starter
是如何配置的, 第三方框架也是相似,因此在下面觀察的過程當中會直接指出相同點,而再也不作對比詳細對比。
這裏選擇 mybatis-spring-boot-starter
進行學習分析。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
複製代碼
這裏 mybatis
框架的 starter
依賴符合必定的規則,即 xxx-spring-boot-starter.
觀察這個 starter
,發現它也沒有作任何的代碼實現,這一點和 springboot
官方一致。
查看 mybatis-spring-boot-starter
的依賴項,有不少,其中和自動配置有關的主要是。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
</dependency>
複製代碼
查看 mybatis-spring-boot-autoconfigure
的內容發現和 springboot
官方的 autoconfigure
結構上是差很少的。
mybatis
的自動配置也是經過 spring.factories
來指明自動配置,而後經過 XxxAutoConfiguration
綁定 XxxProperties
來進行自動配置.
在原理上,和上面 springboot
官方的 starter
是相同的,因此不作過多的介紹了。
說了那麼多,終於到了實操環節,經過上面的介紹,咱們能夠大體得出編寫本身的 starter
步驟。
xxx-spring-boot-starter
的啓動器項目。xxx-spring-boot-autoconfigure
的項目。
xxxProperties
.xxxProperties
.XXXAutoConfiguration
注入配置。spring.factories
文件,用於指定要自動配置的類。xxx-spring-boot-autoconfigure
等其餘依賴。starter
,配置須要配置的信息。因爲啓動器不須要代碼實現,只須要依賴其餘項目,因此直接建立一個空的 maven 項目。可是名字要規範。
這裏建立的 starter
是 myapp-spring-boot-starter
。
pom 文件很是簡單,只須要引入接下來要建立的 myapp-spring-boot-autoconfigure
.
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>net.codingme.starter</groupId>
<artifactId>myapp-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 啓動器 -->
<dependencies>
<!-- 引入自動配置項目 -->
<dependency>
<groupId>net.codingme.starter</groupId>
<artifactId>myapp-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
複製代碼
結合上面對 starter
的分析,直接建立一個名字爲 myapp-spring-boot-autoconfigure
的項目。項目中只引入 springboot
父項目以及 spring-boot-starter
。
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.codingme.starter</groupId>
<artifactId>myapp-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>myapp-spring-boot-autoconfigure</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
複製代碼
項目的整體結構看圖。
在 HelloProperties
中經過註解 @ConfigurationProperties(prefix = "myapp.hello")
讓類中的屬性與 myapp.hello
開頭的配置進行綁定。
/** * <p> * * @Author niujinpeng * @Date 2019/10/29 23:51 */
@ConfigurationProperties(prefix = "myapp.hello")
public class HelloProperties {
private String suffix;
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
複製代碼
而後在 HelloService
中的 sayHello
方法使用 HelloProperties
中自動綁定的值。
public class HelloService {
HelloProperties helloProperties;
public String sayHello(String name) {
return "Hello " + name + "," + helloProperties.getSuffix();
}
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
}
複製代碼
爲了讓 HelloService
能夠自動注入且能正常使用 HelloProperties
,因此咱們在
HelloServiceAutoConfiguration
類中把 HelloProperties.class
引入,而後把 HelloService
注入到 Bean
。
/** * web應用才生效 */
@ConditionalOnWebApplication
/** * 讓屬性文件生效 */
@EnableConfigurationProperties(HelloProperties.class)
/*** * 聲明是一個配置類 */
@Configuration
public class HelloServiceAutoConfiguration {
@Autowired
private HelloProperties helloProperties;
@Bean
public HelloService helloService() {
HelloService helloService = new HelloService();
helloService.setHelloProperties(helloProperties);
return helloService;
}
}
複製代碼
最後在 spring.factories
中只須要指定要自動配置的類便可。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
net.codingme.starter.HelloServiceAutoConfiguration
複製代碼
到這裏,自動配置項目就完成了。能夠在 myapp-spring-boot-autoconfigure
項目執行 mvn install
把自動配置項目打包到本地倉庫,而後使用相同的命令把 myapp-spring-boot-starter
安裝到倉庫。由於後者依賴於前者項目,因此這裏前者須要先進 mvn install
。
建立一個 springboot
項目myapp-spring-boot-starter-test
。
引入 web
依賴,引入本身編寫的 myapp-spring-boot-starter
.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入本身的 starter -->
<dependency>
<groupId>net.codingme.starter</groupId>
<artifactId>myapp-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
複製代碼
編寫一個 HelloController
注入自動配置裏的 HelloService
用於測試。
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String sayHello(String name) {
return helloService.sayHello(name);
}
}
複製代碼
因爲 autoConfigure
項目中定義了 sayHello
方法會輸出「Hello」+傳入的 name + 配置的 hello.suffix
,因此咱們在 springboot
配置文件中配置這個屬性。
myapp.hello.suffix=早上好
複製代碼
運行測試項目,訪問 /hello 路徑傳入一個 name 看看自動配置有沒有生效。
從測試結果能夠看到自動配置的早上好已經生效了。到這裏本身編寫的 starter
也已經完工。
項目已經傳到 Github.
github.com/niumoo/spri…
Springboot 系列(一)Spring Boot 入門
Springboot 系列(二)Spring Boot 配置文件
Springboot 系列(三)Spring Boot 自動配置
Springboot 系列(四)Spring Boot 日誌框架
Springboot 系列(五)Spring Boot web 開發之靜態資源和模版引擎
Springboot 系列(六)Spring Boot web 開發之攔截器和三大組件
Springboot 系列(七)web 開發之異常錯誤處理機制剖析
Springboot 系列(八)動態Banner與圖片轉字符圖案的手動實現
Springboot 系列(九)使用 Spring JDBC 和 Druid 數據源監控
Springboot 系列(十)使用 Spring data jpa 訪問數據庫
Springboot 系列(十一)使用 Mybatis 訪問數據庫
Springboot 系列(十二)使用 Mybatis 集成 pagehelper 分頁插件和 mapper 插件
Springboot 系列(十三)使用郵件服務
Springboot 系列(十四)迅速啓用 HTTPS 加密你的網站
Springboot 系列(十五)如何編寫本身的 Springboot starter
<完>
我的網站:www.codingme.net
若是你喜歡這篇文章,能夠關注公衆號,一塊兒成長。 關注公衆號回覆資源能夠沒有套路的獲取全網最火的的 Java 核心知識整理&面試核心資料