本文摘自於 《Spring Cloud微服務 入門 實戰與進階》 一書。java
Spring Boot的方便體如今簡化了不少繁瑣的配置,對開發人員來講是一個福音,經過引入各類Spring Boot Starter包能夠快速的搭建出一個項目的腳手架。web
目前提供的Spring Boot Starter包有:redis
spring-boot-starter-web:快速構建基於Spring MVC的Web項目,使用Tomcat作默認嵌入式容器。spring
spring-boot-starter-data-redis:操做Redis。sql
spring-boot-starter-data-mongodb:操做Mongodb。mongodb
spring-boot-starter-data-jpa:操做Mysql。json
spring-boot-starter-activemq:操做Activemq。bash
等等......app
自動配置很是方便,當咱們要操做Mongodb的時候,只須要引入spring-boot-starter-data-mongodb的依賴,而後配置Mongodb的連接信息 spring.data.mongodb.uri=mongodb://localhost/test
就可使用MongoTemplate來操做數據,MongoTemplate的初始化工做所有交給Starter來完成。異步
自動配置麻煩的是當出現錯誤時,排查問題的難度上升了。自動配置的邏輯都在Spring Boot Starter中,要快速的可以定位問題,那麼你必須得了解Spring Boot Starter的內部原理。接下來咱們本身動手來實現一個Spring Boot Starter。
開發Starter步驟:
建立Starter項目
定義Starter須要的配置(Properties)類
編寫自動配置類
編寫spring.factories文件加載自動配置類
編寫配置提示文件spring-configuration-metadata.json(不是必須的)
建立一個項目spring-boot-starter-demo,Pom.xml配置以下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
複製代碼
建立一個配置類,用於在屬性文件中配置值,至關於spring.data.mongo這種形式
import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Data;
@Data
@ConfigurationProperties("spring.user")
public class UserPorperties {
private String name;
}
複製代碼
@ConfigurationProperties指定了配置的前綴,也就是spring.user.name=XXX
再定義一個Client,至關於MongoTemplate,裏面定一個方法,用於獲取配置中的值
public class UserClient {
private UserPorperties userPorperties;
public UserClient() {
}
public UserClient(UserPorperties p) {
this.userPorperties = p;
}
public String getName() {
return userPorperties.getName();
}
}
複製代碼
一個最基本的Starter包定義好了,但目前確定是不能使用UserClient ,由於咱們沒有去自動構建UserClient 的實例,接下來開始構建UserClient
@Configuration
@EnableConfigurationProperties(UserPorperties.class)
public class UserAutoConfigure {
@Bean
@ConditionalOnProperty(prefix = "spring.user",value = "enabled",havingValue = "true")
public UserClient userClient(UserPorperties userPorperties) {
return new UserClient(userPorperties);
}
}
複製代碼
Spring Boot會默認掃描跟啓動類平級的包,若是咱們的Starter跟啓動類不在同一個主包下,如何讓UserAutoConfigure 生效?
第一種方式:
在resources下建立一個META-INF文件夾,而後在META-INF文件夾中建立一個spring.factories文件,文件中指定自動配置的類
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.cxytiandi.demo.UserAutoConfigure
複製代碼
Spring Boot啓動時會去讀取spring.factories文件,而後根據配置激活對應的配置類,到底爲止就簡單的實現了一個Starter包。
如今能夠在其餘的項目中引入這個Starter包:
<dependency>
<groupId>com.example</groupId>
<artifactId>spring-boot-starter-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
複製代碼
引入以後就直接可使用UserClient,UserClient 在項目啓動的時候已經自動初始化好。
@RestController
public class UserController {
@Autowired
private UserClient userClient;
@GetMapping("/user/name")
public String getUserName() {
return userClient.getName();
}
}
複製代碼
不少時候咱們不想引入了Starter包就執行初始化的邏輯,想要用戶來指定是否要開啓Starter包的自動配置功能,好比經常使用的@EnableAsync這個註解就是用於開啓調用方法異步執行的功能。
一樣的咱們也能夠經過註解的方式來開啓是否自動配置,若是用註解的方式,那麼spring.factories就不須要編寫了,下面來看怎麼定義啓用自動配置的註解。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({UserAutoConfigure.class})
public @interface EnableUserClient {
}
複製代碼
核心是@Import({UserAutoConfigure.class})這行代碼,經過導入的方式實現把UserAutoConfigure實例加入SpringIOC容器中,這樣就能開啓自動配置了。
使用方式就是在啓動類上加上該註解,代碼入下:
@EnableUserClient
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
複製代碼
在某些場景下,UserAutoConfigure中會配置多個對象,對於這些對象,不想所有配置,也想讓用戶指定須要開啓配置的時候再去構建對象,這個時候咱們能夠經過@ConditionalOnProperty來指定是否開啓配置的功能,代碼以下:
@Bean
@ConditionalOnProperty(prefix = "spring.user",value = "enabled",havingValue = "true")
public UserClient userClient(UserPorperties userPorperties) {
return new UserClient(userPorperties);
}
複製代碼
經過上面的配置,只有當啓動類加了@EnableUserClient而且配置文件中spring.user.enabled=true的時候纔會自動配置UserClient 。
在自定義Starter包的過程當中,還有一點也比較重要,就是須要對配置的內容項進行提示,須要注意的是Eclipse中是不支持提示的,我用的Spring Tools 4 for Eclipse,以下圖:
定義提示內容須要在META-INF中建立一個spring-configuration-metadata.json
{
"properties": [
{
"name": "spring.user.name",
"defaultValue": "cxytinadi"
},
{
"name": "spring.user.enabled",
"type": "java.lang.Boolean",
"defaultValue": false
}
]
}
複製代碼
本文摘自於 《Spring Cloud微服務 入門 實戰與進階》 一書。