springboot 自定义starter类
不論在工作中,亦或是求職面試,Spring Boot已經(jīng)成為我們必知必會(huì)的技能項(xiàng),如今的各行各業(yè)都在飛速的擁抱這個(gè)已經(jīng)不是很新的Spring啟動(dòng)框架。
當(dāng)然,作為Spring Boot的精髓,自動(dòng)配置原理的工作過(guò)程往往只有在“面試”的時(shí)候才能用得上,但是如果在工作中你能夠深入的理解Spring Boot的自動(dòng)配置原理,將無(wú)往不利。
Spring Boot的出現(xiàn),得益于“習(xí)慣優(yōu)于配置”的理念,沒(méi)有繁瑣的配置、難以集成的內(nèi)容(大多數(shù)流行第三方技術(shù)都被集成),這是基于Spring 4.x提供的按條件配置Bean的能力。
自動(dòng)配置原理
Spring Boot關(guān)于自動(dòng)配置的源碼在spring-boot-autoconfigure-x.x.x.x.jar中:
當(dāng)然,自動(dòng)配置原理的相關(guān)描述,官方文檔貌似是沒(méi)有提及。不過(guò)我們不難猜出,Spring Boot的啟動(dòng)類(lèi)上有一個(gè)@SpringBootApplication注解,這個(gè)注解是Spring Boot項(xiàng)目必不可少的注解。那么自動(dòng)配置原理一定和這個(gè)注解有著千絲萬(wàn)縷的聯(lián)系!
@EnableAutoConfiguration
?@SpringBootApplication是一個(gè)復(fù)合注解或派生注解,在@SpringBootApplication中有一個(gè)注解@EnableAutoConfiguration,翻譯成人話就是開(kāi)啟自動(dòng)配置,其定義如下:
?而這個(gè)注解也是一個(gè)派生注解,其中的關(guān)鍵功能由@Import提供,其導(dǎo)入的AutoConfigurationImportSelector的selectImports()方法通過(guò)SpringFactoriesLoader.loadFactoryNames()掃描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一個(gè)這樣的spring.factories文件。
這個(gè)spring.factories文件也是一組一組的key=value的形式,其中一個(gè)key是EnableAutoConfiguration類(lèi)的全類(lèi)名,而它的value是一個(gè)xxxxAutoConfiguration的類(lèi)名的列表,這些類(lèi)名以逗號(hào)分隔,如下圖所示:
這個(gè)@EnableAutoConfiguration注解通過(guò)@SpringBootApplication被間接的標(biāo)記在了Spring Boot的啟動(dòng)類(lèi)上。在SpringApplication.run(...)的內(nèi)部就會(huì)執(zhí)行selectImports()方法,找到所有JavaConfig自動(dòng)配置類(lèi)的全限定名對(duì)應(yīng)的class,然后將所有自動(dòng)配置類(lèi)加載到Spring容器中。
自動(dòng)配置生效
每一個(gè)XxxxAutoConfiguration自動(dòng)配置類(lèi)都是在某些條件之下才會(huì)生效的,這些條件的限制在Spring Boot中以注解的形式體現(xiàn),常見(jiàn)的條件注解有如下幾項(xiàng):
@ConditionalOnBean:當(dāng)容器里有指定的bean的條件下。
@ConditionalOnMissingBean:當(dāng)容器里不存在指定bean的條件下。
@ConditionalOnClass:當(dāng)類(lèi)路徑下有指定類(lèi)的條件下。
@ConditionalOnMissingClass:當(dāng)類(lèi)路徑下不存在指定類(lèi)的條件下。
@ConditionalOnProperty:指定的屬性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表當(dāng)xxx.xxx為enable時(shí)條件的布爾值為true,如果沒(méi)有設(shè)置的情況下也為true。
以ServletWebServerFactoryAutoConfiguration配置類(lèi)為例,解釋一下全局配置文件中的屬性如何生效,比如:server.port=8081,是如何生效的(當(dāng)然不配置也會(huì)有默認(rèn)值,這個(gè)默認(rèn)值來(lái)自于org.apache.catalina.startup.Tomcat)。
在ServletWebServerFactoryAutoConfiguration類(lèi)上,有一個(gè)@EnableConfigurationProperties注解:開(kāi)啟配置屬性,而它后面的參數(shù)是一個(gè)ServerProperties類(lèi),這就是習(xí)慣優(yōu)于配置的最終落地點(diǎn)。
在這個(gè)類(lèi)上,我們看到了一個(gè)非常熟悉的注解:@ConfigurationProperties,它的作用就是從配置文件中綁定屬性到對(duì)應(yīng)的bean上,而@EnableConfigurationProperties負(fù)責(zé)導(dǎo)入這個(gè)已經(jīng)綁定了屬性的bean到spring容器中(見(jiàn)上面截圖)。那么所有其他的和這個(gè)類(lèi)相關(guān)的屬性都可以在全局配置文件中定義,也就是說(shuō),真正“限制”我們可以在全局配置文件中配置哪些屬性的類(lèi)就是這些XxxxProperties類(lèi),它與配置文件中定義的prefix關(guān)鍵字開(kāi)頭的一組屬性是唯一對(duì)應(yīng)的。
至此,我們大致可以了解。在全局配置的屬性如:server.port等,通過(guò)@ConfigurationProperties注解,綁定到對(duì)應(yīng)的XxxxProperties配置實(shí)體類(lèi)上封裝為一個(gè)bean,然后再通過(guò)@EnableConfigurationProperties注解導(dǎo)入到Spring容器中。
而諸多的XxxxAutoConfiguration自動(dòng)配置類(lèi),就是Spring容器的JavaConfig形式,作用就是為Spring 容器導(dǎo)入bean,而所有導(dǎo)入的bean所需要的屬性都通過(guò)xxxxProperties的bean來(lái)獲得。
可能到目前為止還是有所疑惑,但面試的時(shí)候,其實(shí)遠(yuǎn)遠(yuǎn)不需要回答的這么具體,你只需要這樣回答:
Spring Boot啟動(dòng)的時(shí)候會(huì)通過(guò)@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自動(dòng)配置類(lèi),并對(duì)其進(jìn)行加載,而這些自動(dòng)配置類(lèi)都是以AutoConfiguration結(jié)尾來(lái)命名的,它實(shí)際上就是一個(gè)JavaConfig形式的Spring容器配置類(lèi),它能通過(guò)以Properties結(jié)尾命名的類(lèi)中取得在全局配置文件中配置的屬性如:server.port,而XxxxProperties類(lèi)是通過(guò)@ConfigurationProperties注解與全局配置文件中對(duì)應(yīng)的屬性進(jìn)行綁定的。
什么是starter
Starter可以理解為一個(gè)可拔插式的插件,提供一系列便利的依賴(lài)描述符,您可以獲得所需的所有Spring和相關(guān)技術(shù)的一站式服務(wù)。應(yīng)用程序只需要在maven中引入starter依賴(lài),SpringBoot就能自動(dòng)掃描到要加載的信息并啟動(dòng)相應(yīng)的默認(rèn)配置。用一句話描述,就是springboot的場(chǎng)景啟動(dòng)器。
下面是Spring官方提供的部分starter,全部的請(qǐng)參考官網(wǎng):
?
自定義starter
官方定義的starter命名都是spring-boot-starter-xxx,我們自己定義的一般都 xxx-spring-boot-starter,新建一個(gè)id-gengerate-spring-boot-starter項(xiàng)目
導(dǎo)入springboot 包spring-boot-starter
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!--主要是為了生成spring-configration-metadata.json文件,方便idea跳轉(zhuǎn)--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies>1.創(chuàng)建配置類(lèi),定義一個(gè)映射配置新的的類(lèi)IdProperties和LockieProperties,添加注解ConfigurationProperties("machine.id"),我們的配置文件以machine.id開(kāi)頭,比如mathine.id.name=boot-order,另外一個(gè)配置文件是已spring.lockie開(kāi)頭的配置文件
package com.lockie.starter.config;import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties;/*** @author: lockie* @Date: 2020/11/3 15:10* @Description: id生成配置類(lèi)*/ @Data @ConfigurationProperties("machine.id") public class IdProperties {private String name; }package com.lockie.starter.config;import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties;/*** @author: 鄒細(xì)良* @Date: 2020/11/3 18:21* @Description:*/ @Data @ConfigurationProperties("spring.lockie") public class LockieProperties {private String prefix;private String suffix; }2.創(chuàng)建一個(gè)接口用來(lái)生成對(duì)應(yīng)的業(yè)務(wù),IdService里面有個(gè)getId方法用來(lái)生成自定義的ID
package com.lockie.starter.service;import com.lockie.starter.config.IdProperties; import lombok.Data;/*** @author: lockie* @Date: 2020/11/3 15:19* @Description: 生成ID接口*/ @Data public class IdService {private IdProperties idProperties;/*** 獲取ID* @return*/public String getId() {return idProperties.getName() + "-" + System.currentTimeMillis();} }package com.lockie.starter.service;import com.lockie.starter.config.LockieProperties; import lombok.Data;/*** @author: lockie* @Date: 2020/11/3 18:23* @Description:*/ @Data public class LockieService {LockieProperties lockieProperties;public String hello(String name) {return lockieProperties.getPrefix() + "-" + name + "-" + lockieProperties.getSuffix();} }3.創(chuàng)建配置類(lèi),重要的配置參數(shù)
@Configuration:配置類(lèi)
@EnableConfigurationProperties():開(kāi)啟某屬性類(lèi),里面封裝的是屬性信息,相當(dāng)于@ConfigurationProperties加載application.properties里面的信息,并用@Component將類(lèi)交由spring管理
@ConditionalOnClass():當(dāng)這個(gè)類(lèi)存在時(shí),再進(jìn)行下面的步驟,否則就不進(jìn)行下面的步驟了
@AutoConfigureAfter():當(dāng)自動(dòng)配置完成后,再執(zhí)行里面的類(lèi)
@ConfigurationOnMissBean():當(dāng)這個(gè)bean不存在時(shí),再添加bean類(lèi)
@Bean:添加bean類(lèi)
4.最重要的一步,在resources目錄下創(chuàng)建META-INF目錄,并添加文件spring.factories。在這個(gè)文件中配置EnableAutoConfiguration,具體如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.lockie.starter.config.IdAutoConfiguation,\com.lockie.starter.config.LockieAutoConfiguration測(cè)試自定義的Starter?
我們?cè)谥暗捻?xiàng)目boot-order-service中測(cè)試我們的starter, boot-order-service項(xiàng)目pom增加id-generate-spring-boot-starter包
<dependency><groupId>com.lockie-starter</groupId><artifactId>id-generate-spring-boot-starter</artifactId><version>0.0.1-SNAPSHOT</version> </dependency>項(xiàng)目包路徑一樣可能還需要在boot-order-starter啟動(dòng)類(lèi)上增加掃描id-generate-spring-boot-starter項(xiàng)目包路徑?
@SpringBootApplication(scanBasePackages = "com.lockie.starter")boot-order-service項(xiàng)目配置文件增加配置參數(shù)
machine.id.name=boot-order spring.lockie.prefix=Hello! spring.lockie.suffix=Nice to meet you到這里我們?cè)赽oot-order-service服務(wù)中就可以使用id-generate-spring-boot-starter項(xiàng)目中的services了,并且只需要使用@Autowired即可
@SpringBootTest @ContextConfiguration(classes = BootOrderServiceApplication.class) class BootOrderServiceApplicationTests {@Testvoid contextLoads() {}@AutowiredIdService idService;@AutowiredLockieService lockieService;@Testpublic void testIdGenerate() {String id = idService.getId();System.out.println("生成ID:" + id);String str = lockieService.hello("小明");System.out.println("打招呼:"+ str);} }運(yùn)行一下查看結(jié)果,看到結(jié)果是我們想要的,至此我們自定義一個(gè)starter就成功了,總結(jié)一下就是要?jiǎng)?chuàng)建3個(gè)類(lèi)1個(gè)配置文件,xxProperties,xxService,xxAutoConfiguation和spring.factories
總結(jié)
以上是生活随笔為你收集整理的springboot 自定义starter类的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 读书笔记:时间与精力管理:你的精力管理决
- 下一篇: 流氓软件,终于被爆出来了