前面我們簡單介紹了如何使用消息中間件 Apache Pulsar ,但是在項(xiàng)目中那樣使用,顯然是不太好的,不管從易用性和擴(kuò)展性來看,都是遠(yuǎn)遠(yuǎn)不夠, 為了和springboot項(xiàng)目集成,寫一個(gè)pulsar-spring-boot-starter是非常有必要的,在此之前,我們先看看一個(gè)starter需要些什么。
Spring Boot Starter
spring-boot的強(qiáng)大之處在于其提供的大量starter組件,基本涵蓋了我們開發(fā)中的各個(gè)技術(shù)領(lǐng)域,比如數(shù)據(jù)庫訪問有jdbc、jpa,緩存有redis,全文檢索有elasticsearch,消息隊(duì)列有amqp、kafka等等。
在項(xiàng)目中你只需要按需引入相應(yīng)的依賴 spring-boot-starter-xxx ,然后只需要替換對(duì)應(yīng)的配置參數(shù)即可,就能快速使用對(duì)應(yīng)的功能,不得不說簡直是為開發(fā)者插上了翅膀。
命名風(fēng)格
對(duì)于starter模塊如何命名,spring官方是這樣建議:
- Spring官方命名格式為:spring-boot-starter-{name}
- 非Spring官方建議命名格式:{name}-spring-boot-starter
準(zhǔn)備工作
如果你之前有看過spring官方starter組件,你會(huì)發(fā)現(xiàn)主要是基于AutoConfigure及@Enable來實(shí)現(xiàn)的。
- 其中AutoConfigure也就是我們常說的自動(dòng)裝配,在spring-boot-autoconfigure包中的目錄/METE-INF/spring.factories對(duì)應(yīng)文件中,你可以看到這樣的配置:
當(dāng)啟動(dòng)Spring Boot項(xiàng)目時(shí)這些配置都會(huì)被加載(這么多的配置全部加載并處理,難怪啟動(dòng)那么慢)。
在starter中依賴的具體實(shí)現(xiàn)包中,一般都會(huì)提供一個(gè)@Enable注解作為部分?jǐn)U展功能的開關(guān),我們可以在系統(tǒng)中通過該注解引入按需引入配置
AutoConfigure配置的一定會(huì)被加載,而@Enable有開發(fā)者選擇使用使用,當(dāng)然有些組件是沒有AutoConfigure,必須通過@Enable來啟用
下面我們先對(duì)這塊內(nèi)容做個(gè)簡單的認(rèn)識(shí),方便后續(xù)在寫具體starter時(shí)知道怎么寫以及為什么那樣寫。
AutoConfigure
在目錄中創(chuàng)建src/main/resources/MATE-INF中創(chuàng)建文件spring.factories,定義SpringBoot應(yīng)用啟動(dòng)時(shí)的需要注冊(cè)的配置,這個(gè)主要是基于SPI機(jī)制來實(shí)現(xiàn), 下面是當(dāng)前spring-boot-autoconfigure中spring.factories文件的部分內(nèi)容
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,
...
配置在這里的帶有@Configuration的類(如果沒有被Conditional條件過濾掉)都會(huì)作為配置將相關(guān)Bean注冊(cè)到Spring容器.
主要實(shí)現(xiàn)基于@SpringBootApplication注解上的注解@EnableAutoConfiguration
Enable
以Spring Aop相關(guān)的注解@EnableAspectJAutoProxy為例,我們看下 Spring官方是怎么使用@Enable注解來實(shí)現(xiàn)配置加載的:
@EnableAspectJAutoProxy
改注解除了一般注解的基礎(chǔ)(@Target、@Retention)元素外,還包含了兩個(gè)配置屬性proxyTargetClass、exposeProxy以及一個(gè)@Import
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
@Import
在@Import中我們可以配置需要導(dǎo)入的配置類,有以下幾個(gè)選擇:
- 直接導(dǎo)入@Configuration標(biāo)識(shí)的類
- 導(dǎo)入實(shí)現(xiàn)了接口ImportBeanDefinitionRegistrar的類,來向容器注冊(cè)BeanDefinition
- 導(dǎo)入實(shí)現(xiàn)了接口ImportSelector的類(不需要@Configuration)來選擇配置
@Import(AspectJAutoProxyRegistrar.class)
ImportBeanDefinitionRegistrar
在上面@EnableAspectJAutoProxy注解上,通過@Import,引入了AspectJAutoProxyRegistrar,而該類又實(shí)現(xiàn)了接口ImportBeanDefinitionRegistrar, 該接口能夠通過BeanDefinitionRegistry向Spring容器注冊(cè)我們期望的BeanDefinition,看代碼:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
這里我們可以拿到@EnableAspectJAutoProxy的元數(shù)據(jù)以及對(duì)應(yīng)的屬性配置,這樣就可以基于開發(fā)者的配置實(shí)現(xiàn)不同邏輯
ImportSelector
上面說到了,@Import還可以配置實(shí)現(xiàn)了ImportSelector接口的類,進(jìn)而控制具體需要使用的Configuration,下面是@EnableAsync中@Import配置的類
public class AsyncConfigurationSelector extends AdviceModeImportSelector< EnableAsync > {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
ImportAware
同樣和@Import配合使用,針對(duì)基于ImportSelector選擇的Configuration,只要實(shí)現(xiàn)了ImportAware接口,就可以拿到@Import對(duì)應(yīng)@Enable注解的元數(shù)據(jù)
@Configuration
public abstract class AbstractAsyncConfiguration implements ImportAware {
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableAsync = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
if (this.enableAsync == null) {
throw new IllegalArgumentException(
"@EnableAsync is not present on importing class " + importMetadata.getClassName());
}
}
}
上面主要根據(jù)Spring源代碼中的例子,了解@Enable、@Import、ImportBeanDefinitionRegistrar、ImportSelector、ImportAware如何搭配使用, 從而實(shí)現(xiàn)Spring的動(dòng)態(tài)配置,用一張關(guān)系圖表示:
relation
其他擴(kuò)展
spring-boot-configuration-processor
我們知道SpringBoot的配置我們都會(huì)寫在application.yml(.properties)文件中,為了簡化配置工作,如果能有智能提示就好了。這不,別人也想到了。只用這樣做:
- 現(xiàn)在只需要在項(xiàng)目中引入依賴:
< dependency >
< groupId >org.springframework.boot< /groupId >
< artifactId >spring-boot-configuration-processor< /artifactId >
< optional >true< /optional >
< /dependency >
- 定義一個(gè)Properties文件
@Data
@ConfigurationProperties(prefix = "myProp")
public class MyProperties {
private Boolean enable;
private String name;
}
- 在Configuration中導(dǎo)入
@Configuration
@EnableConfigurationProperties({MyProperties.class})
public class WebApiAutoConfiguration {
}
- 打包
mvn clean install
- 生產(chǎn)metadata.json 可以看到,在jar中的/META-INF目錄下多了一個(gè)spring-configuration-metadata.json文件
@Conditional
實(shí)現(xiàn)spring bean的可插拔,我們可以基于屬性、配置、類或者Bean來控制配置(@Configuration)是否生效,常見的有下面的這些:
- ConditionalOnBean 容器存在Bean時(shí)配置有效
- ConditionalOnClass classpath中有指定class時(shí)配置有效
- ConditionalOnMissingBean 容器不存在Bean時(shí)配置有效
- ConditionalOnMissingClass classpath中沒有指定class時(shí)配置有效
- ConditionalOnProperty 屬性配置對(duì)應(yīng)值成立時(shí)配置有效
AutoConfigure和@Enable
AutoConfigure是在spring.factories中配置了就會(huì)加載,但是可以通過@Conditional讓配置中的Bean不生效;@Enable需要顯示地使用才能有效,且先于AutoConfigure生效,從而可以配合@Conditional來阻斷AutoConfigure的配置
結(jié)束語
關(guān)于Spring框架的學(xué)習(xí)后面會(huì)慢慢增多,我們會(huì)從原理到實(shí)踐來介紹其功能,如果你有感興趣的技術(shù)點(diǎn)或者開發(fā)中的問題,可以通過留言進(jìn)行交流分享。
-
SPI
+關(guān)注
關(guān)注
17文章
1706瀏覽量
91578 -
緩存
+關(guān)注
關(guān)注
1文章
240瀏覽量
26678 -
數(shù)據(jù)庫
+關(guān)注
關(guān)注
7文章
3799瀏覽量
64388 -
spring
+關(guān)注
關(guān)注
0文章
340瀏覽量
14343 -
Starter
+關(guān)注
關(guān)注
0文章
8瀏覽量
7545
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論