之前熟悉了SpringBoot的自動配置原理,相關連結:SpringBoot學習之自動配置原理,今天來玩一下自定義起步依賴starter。
一、分析
以jdbc下DataSource自動配置參考為例:
1.DataSourceAutoConfiguration
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
...
2.DataSourceProperties
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties
implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {
private ClassLoader classLoader;
private Environment environment;
...
3.spring.factories配置

4.總結
(1)自動配置的大體流程
1)@Configuration //指定一個配置類
2)@Conditionalxxx //在指定條件成立時自動配置類生效
3)@EnableConfigurationProperties //讓xxxProperties檔案生效并加入到容器
4)@ConfigurationProperties //注解相關xxxProperties檔案來綁定相關屬性
5)在META-INF 下的spring.factories中配置該自動配置類
(2)開始自定義starter
接下來分兩步走:
- 第一是自定義starter并調試,在一個工程中驗證;
- 第二是參照其他起步依賴配置模式打包生成自己的起步依賴starter
二、編寫starter并調試
以自定義HttpClient自動配置為例:
1、建立一個Springboot工程
2、導入httpclient依賴
<!--導入httpclient依賴-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
3、建立HttpClientProperties
/**
* @description: httpclient 屬性配置類
* 在application.properties中進行配置,可以覆寫各屬性的預設值
* @author: zrk
* @create: 2019-03-08
*/
@ConfigurationProperties(prefix = "zrk.httpclient")
public class HttpClientProperties {
private Integer connectTimeOut = 1000;
private Integer socketTimeOut = 10000;
private String agent = "agent";
private Integer maxConnPreRoute = 10;
private Integer maxConnTotal = 50;
public Integer getConnectTimeOut() {
return connectTimeOut;
}
public void setConnectTimeOut(Integer connectTimeOut) {
this.connectTimeOut = connectTimeOut;
}
public Integer getSocketTimeOut() {
return socketTimeOut;
}
public void setSocketTimeOut(Integer socketTimeOut) {
this.socketTimeOut = socketTimeOut;
}
public String getAgent() {
return agent;
}
public void setAgent(String agent) {
this.agent = agent;
}
public Integer getMaxConnPreRoute() {
return maxConnPreRoute;
}
public void setMaxConnPreRoute(Integer maxConnPreRoute) {
this.maxConnPreRoute = maxConnPreRoute;
}
public Integer getMaxConnTotal() {
return maxConnTotal;
}
public void setMaxConnTotal(Integer maxConnTotal) {
this.maxConnTotal = maxConnTotal;
}
}
4、建立HttpClientAutoConfiguration
/**
* @description: httpclient自動配置類
* @author: zrk
* @create: 2019-03-08
*/
@Configuration //配置類
@ConditionalOnClass({HttpClient.class}) //生效條件是HttpClient存在
@EnableConfigurationProperties(HttpClientProperties.class) //讓配置檔案生效并加入到容器
public class HttpClientAutoConfiguration {
private final HttpClientProperties httpClientProperties;
public HttpClientAutoConfiguration(HttpClientProperties httpClientProperties) {
this.httpClientProperties = httpClientProperties;
}
@Bean
@ConditionalOnMissingBean(HttpClient.class) //當容器中不存在HttpClient實力時此bean才加入容器
public HttpClient httpClient(){
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(httpClientProperties.getConnectTimeOut())
.setSocketTimeout(httpClientProperties.getSocketTimeOut())
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setMaxConnPerRoute(httpClientProperties.getMaxConnPreRoute())
.setMaxConnTotal(httpClientProperties.getMaxConnTotal())
.setUserAgent(httpClientProperties.getAgent())
.build();
}
}
5、編寫測試類并運作
@RunWith(SpringRunner.class)
@SpringBootTest
public class HttpclientApplicationTests {
@Resource
HttpClient httpClient;
@Test
public void httpclientTest() throws IOException {
System.out.println(EntityUtils.toString(httpClient.execute(new HttpGet("http://www.baidu.com")).getEntity()));
}
}
運作測試方法,控制台如下:
如圖,可以正常通路并列印,證明自動配置已經生效。
但是現在暫未在META-INF中進行配置,自動配置生效是因為根據SpringBoot包掃描原理會掃描主啟動類所在目錄及以下目錄的包(可以參考SpringBoot學習之包掃描),配置類在此子包中是以可以掃描到容器。
但作為起步依賴包讓其他項目用是不再包掃描範圍内的,接下來就用兩種方式示範在掃描包之外路徑如何使自動配置生效:
(1)在META-INF/spring.properties中配置
修改包名
移動包使其不在自動包掃描範圍内
運作測試方法,報錯,就是因為沒有在容器中找到HttpClient的bean執行個體
建立META-INF/spring.properties檔案并配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zrk.httpclient1.autoconfigure.HttpClientAutoConfiguration
運作測試方法,成功:
(2)自定義注解
參考@EnableAsync方式:
先将META-INF/spring.properties删除或改名使其不生效,再建立EnableHttpClient annotation
在主啟動類上添加@EnableHttpClient注解
運作測試方法,成功:
三、正式編寫starter并打包
參考MyBatis起步依賴模式:
- 啟動器做依賴導入
- 編寫自動配置子產品
-
啟動器依賴自動配置
這樣需要依賴MyBatis時隻需導入啟動器starter即可,也可以直接寫自動配置子產品
自定義starter命名參考:
mybatis-spring-boot-starter -> 功能-spring-boot-starter
1、建立個空工程
2、添加兩個modules
(1)啟動器
(2)自動配置子產品
直至建立完成,點OK
3、在啟動器pom檔案中引入自動配置子產品的坐标依賴
4、編寫自動配置子產品代碼
添加自動配置類、添加屬性配置類、添加META-INF/spring.factories檔案,可以參考上面,這裡不再贅述
因為是作為第三方依賴,是以測試依賴跟相關插件等依賴可以删除
5、打包
先打包自動配置子產品,再打包啟動器
6、建立新工程導入自定義starter進行測試
導入自定義starter:
<!--導入自定義starter-->
<dependency>
<groupId>com.zrk.autoconfigure</groupId>
<artifactId>httpclient-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
建立controller:
@RestController
public class HttpClientController {
@Resource
private HttpClient httpClient;
@RequestMapping("goto")
public String request(){
try {
return EntityUtils.toString(httpClient.execute(new HttpGet("http://www.baidu.com")).getEntity());
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
啟動項目,通路http://localhost:8080/goto,雖有中文亂碼,但是自動配置是生效了~
打斷點,調試如下
修改application.properties
zrk.httpclient.connectTimeOut=2000
zrk.httpclient.socketTimeOut=20000
重新開機項目,通路調試如下
四、總結
總之,參考源代碼,了解架構的設計思路,并按照總結的方式一步步跟着玩,就可以學會自定義starter。