一、什么是Starter?
在開發過程中我們就經常使用到各種starter,比如mybatis-spring-boot-starter,只需要進行簡單的配置即可使用,就像一個插件非常方便。這也是SpringBoot非常重要的一個特性——自動化配置。
二、實現
2.1創建一個maven項目並配置pom.xml
命名規范: Spring官方的Starter命名格式一般是spring-boot-starter-{name},比如spring-boot-starter-web 。而非官方的,官方建議artifactId命名應該遵循 {name}-spring-boot-starter的格式,如example-spring-boot-starter。
pom文件
- "1.0" encoding="UTF-8" xml version=
- <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>cn.sp</groupId>
- <artifactId>example-spring-boot-starter</artifactId>
- <version>1.0-SNAPSHOT</version>
- <properties>
- <spring-boot.version>2.1.5.RELEASE</spring-boot.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-configuration-processor</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-autoconfigure</artifactId>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <!-- Import dependency management from Spring Boot -->
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-dependencies</artifactId>
- <version>${spring-boot.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- </project>
spring-boot-configuration-processor 的作用是編譯時生成 spring-configuration-metadata.json ,此文件主要給IDE使用,ctlr+鼠標左鍵點擊配置文件(如application.properties)上相關配置屬性,即可跳轉到配置此屬性的類中。
我們要實現的一個小功能是讀取配置文件上cn.sp.config的字符串,然后按照給定的分隔符進行分割。
2.2編寫配置文件讀取類
@ConfigurationProperties(prefix = "cn.sp")
public class StarterServiceProperties {
private String config;
public String getConfig() {
return config;
}
public void setConfig(String config) {
this.config = config;
}
}
2.3編寫Service
public class StarterService {
private String config;
public StarterService(String config){
this.config = config;
}
public String[] split(String separatorChar){
return this.config.split(separatorChar);
}
}
2.4編寫自動配置類(重點)
- package cn.sp.autoconfigure;
- 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 2YSP on 2019/5/22.
- */
- (StarterService.class)
- //@ConditionalOnProperty(prefix = "cn.sp",value = "enable",matchIfMissing = true)
- (StarterServiceProperties.class)
- public class StarterAutoConfigure {
- private StarterServiceProperties properties;
- "cn.sp",value = "enabled",havingValue = "true") (prefix =
- StarterService starterService(){
- return new StarterService(properties.getConfig());
- }
- }
說下這幾個注解的作用:
- @ConditionalOnClass:當classpath下發現該類的情況下進行自動配置。
- @EnableConfigurationProperties:使使用 @ConfigurationProperties 注解的類生效。具體可以參考https://www.jianshu.com/p/7f54da1cb2eb
- @ConditionalOnMissingBean:當Spring上下文中不存在該Bean時生效。
- @ConditionalOnProperty(prefix = "cn.sp",value = "enabled",havingValue = "true"),當配置文件中cn.sp.enabled=true時有效。
下面列舉SpringBoot中的所有@Conditional注解及作用
@ConditionalOnBean:當容器中有指定的Bean的條件下
@ConditionalOnClass:當類路徑下有指定的類的條件下
@ConditionalOnExpression:基於SpEL表達式作為判斷條件
@ConditionalOnJava:基於JVM版本作為判斷條件
@ConditionalOnJndi:在JNDI存在的條件下查找指定的位置
@ConditionalOnMissingBean:當容器中沒有指定Bean的情況下
@ConditionalOnMissingClass:當類路徑下沒有指定的類的條件下
@ConditionalOnNotWebApplication:當前項目不是Web項目的條件下
@ConditionalOnProperty:指定的屬性是否有指定的值
@ConditionalOnResource:類路徑下是否有指定的資源
@ConditionalOnSingleCandidate:當指定的Bean在容器中只有一個,或者在有多個Bean的情況下,用來指定首選的Bean
@ConditionalOnWebApplication:當前項目是Web項目的條件下
2.5創建spring.factories
在 resources/META-INF/ 文件夾下創建spring.factories文件,內容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.sp.autoconfigure.StarterAutoConfigure
右邊的就是自動配置類的類路徑,注意單詞別打錯了,我就是META-INF打成了MATA-INF害我折騰了半天。
三、測試
- 執行mvn install命令打包到本地
- 在另外一個項目添加依賴
<dependency>
<groupId>cn.sp</groupId>
<artifactId>example-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
然后可以看到jar包的結構圖如下:
3. 在application.properties文件添加如下內容
cn.sp.enabled=true
cn.sp.config=fdafdf,ss1,DSDS,DDD
- 編寫測試類並啟動
@RunWith(SpringRunner.class)
@SpringBootTest
public class MySpringbootApplicationTests {
@Autowired
StarterService starterService;
@Test
public void contextLoads() {
String[] strings = starterService.split(",");
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i]);
}
}
}
- 運行結果如下則表示成功。
2019-05-23 10:41:49.219 [main] INFO cn.sp.MySpringbootApplicationTests - Started MySpringbootApplicationTests in 10.977 seconds (JVM running for 13.035)
fdafdf
ss1
DSDS
DDD
2019-05-23 10:41:52.411 [Thread-4] INFO o.s.w.c.s.GenericWebApplicationContext - Closing org.springframework.web.context.support.GenericWebApplicationContext@51f49060: startup date [Thu May 23 10:41:38 CST 2019]; root of context hierarchy
四、原理
1.在應用程序啟動過程中,Spring Boot使用SpringFactoriesLoader類加載器查找org.springframework.boot.autoconfigure.EnableAutoConfiguration關鍵字對應的Java配置文件。Spring Boot會遍歷在各個jar包中META-INF目錄下的spring.factories文件,構建成一個配置文件鏈表。
2.根據spring.factories配置加載AutoConfigure類
3.根據 @Conditional注解的條件,進行自動配置並將Bean注入Spring Context中。
注意: Spring Boot的starter在編譯時不需要依賴Spring Boot的庫。
代碼地址:https://github.com/2YSP/example-spring-boot-starter
參考:
https://juejin.im/entry/58d37630570c350058c2c15c
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html