做者:追夢1819
原文:https://www.cnblogs.com/yanfei1819/p/11058502.html
版權聲明:本文爲博主原創文章,轉載請附上博文連接!
html
這一段時間項目趕進度,故該系列博客更新沒有以前那麼頻繁,望諒解。java
SpringBoot 用起來方便,它默認集成了 Java 的主流框架。這也是 SpringBoot 的一大特點,使用方便,須要什麼框架或者技術,只須要引入對應的 starter 便可。目前官方已經集成的各大技術的啓動器,能夠查看 文檔。git
做者最開始考慮該話題的是曾經的一個面試題:如何自定義一個自定義啓動器?github
本文將圍繞該面試題進行講解。面試
在自定義 starter 以前,咱們先回顧 SpringBoot 官方已經集成的 starter 。咱們使用時,只需引入對應的 spring-boot-starter-xxx
便可使用(即咱們常說的開箱即用)。spring
同時,還預先設置了默認值,若是須要修改這些默認值,只須要在 application.properties 或 application.yml 配置文件中修改。例如:SpringBoot 默認的端口號是 8080,若是須要修改該端口號,只須要在 application.properties 中添加屬性 server.port=9090
便可。springboot
建立自定義啓動器,須要建立如下兩個組件:app
首先,建立自定義starter工程,並引入maven依賴:框架
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>2.0.0.RELEASE</version> <optional>true</optional> </dependency>
而後,建立實體類。前綴加上字段名稱能夠在application.properties文件中建立屬性的名稱。maven
package com.yanfei1819.springbootstarter.entity; import org.springframework.boot.context.properties.ConfigurationProperties; /** * Created by 追夢1819 on 2019-05-10. */ @ConfigurationProperties(prefix = "spring.person") public class PersonProperties { private String name; private int age; private double salary; // set/get 省略 }
第三步,定義核心服務類,該類主要定義了 starter 的核心功能。
package com.yanfei1819.springbootstarter.service; import com.yanfei1819.springbootstarter.entity.PersonProperties; /** * Created by 追夢1819 on 2019-05-10. */ public class PersonService { private PersonProperties properties; public PersonService(PersonProperties properties) { this.properties = properties; } public PersonService() { } public void say() { System.out.println("hello,I am " + properties.getName() + ",and I am " + properties.getAge() + ",and My salary " + properties.getSalary()); } }
第四步,自定義配置類。一般狀況每一個 starter 至少有一個配置類。命名規則也很明顯,通常命名規則使用XxxAutoConfiguration, 例如 RedisAutoConfiguration 等。該類將核心功能注入到 SpringBoot 上下文中。
package com.yanfei1819.springbootstarter.configuration; import com.yanfei1819.springbootstarter.entity.PersonProperties; import com.yanfei1819.springbootstarter.service.PersonService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Created by 追夢1819 on 2019-05-10. */ @Configuration @EnableConfigurationProperties(PersonProperties.class) @ConditionalOnClass(PersonService.class) @ConditionalOnProperty(prefix = "spring.person", value = "enabled", matchIfMissing = true) public class PersonServiceAutoConfiguration { @Autowired private PersonProperties properties; @Bean @ConditionalOnMissingBean(PersonService.class) // 當容器中沒有指定Bean的狀況下,自動配置PersonService類 public PersonService personService() { PersonService personService = new PersonService(properties); return personService; } }
最後,建立 spring.factories 文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yanfei1819.springbootstarter.configuration.PersonServiceAutoConfiguration
當 SpringBoot 啓動的時候,它會在類路徑中查找 spring.factories 文件,此條件初始化由@ConditionalOnClass註釋啓用。此文件將名稱映射到Spring Boot將嘗試運行的不一樣配置類。所以,根據這個片斷,Spring Boot將嘗試運行RabbitMQ,Cassandra,MongoDB和Hibernate的全部配置類。
@EnableAutoConfiguration 的關鍵功能是使用 SpringFactoriesLoader.loadFactoryNames 方法來掃描具備 META-INF/spring.factories 文件的 jar 包,這樣咱們的自動配置類才能生效,因此咱們在 autoconfigure 模塊的 resources 下建立 META-INF/spring.factories 文件。
新建立一個工程,引入自定義啓動器的 maven 依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>com.yanfei1819</groupId> <artifactId>customize-spring-boot-starter</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
此處咱們要注意一下命名規則,官方命名是spring-boot-starter-xxx
, 自定義命名是 xxx-spring-boot-starter
。
而後再配置文件中寫入測試數據:
spring.person.name=starter spring.person.age=26
下面咱們修改啓動類作個簡單的測試:
package com.yanfei1819.customizestartertest; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class CustomizeStarterTestApplication implements CommandLineRunner { @Value("${spring.person.name}") private String name; @Value("${spring.person.age}") private int age; public static void main(String[] args) { SpringApplication.run(CustomizeStarterTestApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println("姓名是:"+name+",年齡是:"+age); } }
上面的啓動類實現了 CommandLineRunner 接口,並重寫了 run 方法。Spring boot的CommandLineRunner
接口主要用於實如今應用初始化後,去執行一段代碼塊邏輯,這段初始化代碼在整個應用生命週期內只會執行一次。(該接口的做用能夠參照官網說明)。
此處是爲了省去寫測試類才實現了該接口。
最後,啓動項目,能夠看到以下結果:
根據以上的分析和示例,能夠大概總結出 starter 的工做流程:
SpringBoot 啓動時尋找含 spring.factories 文件的JAR包;
讀取spring.factories文件獲取配置的自動配置類AutoConfiguration;
將自動配置類下知足條件(@ConditionalOnXxx)的@Bean放入到 Springoot 上下文中;
開發者直接使用。
SpringBoot 的自定義啓動器極大的方便了獨立功能 jar 的開發,消除了大量的配置工做。
依葫蘆畫瓢,要寫一個自定義的starter,其實很簡單,注意幾個註解就能夠了。可是,咱們真正要作的,是經過源碼來理解自動配置原理,原理是靈魂,知其然,知其因此然,這樣去自定義 starter 纔會駕輕就熟。後續咱們將繼續分享 SpringBoot 的自動配置原理。