前面我們簡單介紹了如何使用消息中間件 Apache Pulsar ,但是在項目中那樣使用,顯然是不太好的,不管從易用性和擴展性來看,都是遠遠不夠, 為了和springboot項目集成,寫一個pulsar-spring-boot-starter是非常有必要的,在此之前,我們先看看一個starter需要些什么。
Spring Boot Starter
spring-boot的強大之處在于其提供的大量starter組件,基本涵蓋了我們開發中的各個技術領域,比如數據庫訪問有jdbc、jpa,緩存有redis,全文檢索有elasticsearch,消息隊列有amqp、kafka等等。
在項目中你只需要按需引入相應的依賴 spring-boot-starter-xxx ,然后只需要替換對應的配置參數即可,就能快速使用對應的功能,不得不說簡直是為開發者插上了翅膀。
命名風格
對于starter模塊如何命名,spring官方是這樣建議:
- Spring官方命名格式為:spring-boot-starter-{name}
- 非Spring官方建議命名格式:{name}-spring-boot-starter
準備工作
如果你之前有看過spring官方starter組件,你會發現主要是基于AutoConfigure及@Enable來實現的。
- 其中AutoConfigure也就是我們常說的自動裝配,在spring-boot-autoconfigure包中的目錄/METE-INF/spring.factories對應文件中,你可以看到這樣的配置:
當啟動Spring Boot項目時這些配置都會被加載(這么多的配置全部加載并處理,難怪啟動那么慢)。
在starter中依賴的具體實現包中,一般都會提供一個@Enable注解作為部分擴展功能的開關,我們可以在系統中通過該注解引入按需引入配置
AutoConfigure配置的一定會被加載,而@Enable有開發者選擇使用使用,當然有些組件是沒有AutoConfigure,必須通過@Enable來啟用
下面我們先對這塊內容做個簡單的認識,方便后續在寫具體starter時知道怎么寫以及為什么那樣寫。
AutoConfigure
在目錄中創建src/main/resources/MATE-INF中創建文件spring.factories,定義SpringBoot應用啟動時的需要注冊的配置,這個主要是基于SPI機制來實現, 下面是當前spring-boot-autoconfigure中spring.factories文件的部分內容
# 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條件過濾掉)都會作為配置將相關Bean注冊到Spring容器.
主要實現基于@SpringBootApplication注解上的注解@EnableAutoConfiguration
Enable
以Spring Aop相關的注解@EnableAspectJAutoProxy為例,我們看下 Spring官方是怎么使用@Enable注解來實現配置加載的:
@EnableAspectJAutoProxy
改注解除了一般注解的基礎(@Target、@Retention)元素外,還包含了兩個配置屬性proxyTargetClass、exposeProxy以及一個@Import
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
@Import
在@Import中我們可以配置需要導入的配置類,有以下幾個選擇:
- 直接導入@Configuration標識的類
- 導入實現了接口ImportBeanDefinitionRegistrar的類,來向容器注冊BeanDefinition
- 導入實現了接口ImportSelector的類(不需要@Configuration)來選擇配置
@Import(AspectJAutoProxyRegistrar.class)
ImportBeanDefinitionRegistrar
在上面@EnableAspectJAutoProxy注解上,通過@Import,引入了AspectJAutoProxyRegistrar,而該類又實現了接口ImportBeanDefinitionRegistrar, 該接口能夠通過BeanDefinitionRegistry向Spring容器注冊我們期望的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的元數據以及對應的屬性配置,這樣就可以基于開發者的配置實現不同邏輯
ImportSelector
上面說到了,@Import還可以配置實現了ImportSelector接口的類,進而控制具體需要使用的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配合使用,針對基于ImportSelector選擇的Configuration,只要實現了ImportAware接口,就可以拿到@Import對應@Enable注解的元數據
@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());
}
}
}
上面主要根據Spring源代碼中的例子,了解@Enable、@Import、ImportBeanDefinitionRegistrar、ImportSelector、ImportAware如何搭配使用, 從而實現Spring的動態配置,用一張關系圖表示:
relation
其他擴展
spring-boot-configuration-processor
我們知道SpringBoot的配置我們都會寫在application.yml(.properties)文件中,為了簡化配置工作,如果能有智能提示就好了。這不,別人也想到了。只用這樣做:
- 現在只需要在項目中引入依賴:
< dependency >
< groupId >org.springframework.boot< /groupId >
< artifactId >spring-boot-configuration-processor< /artifactId >
< optional >true< /optional >
< /dependency >
- 定義一個Properties文件
@Data
@ConfigurationProperties(prefix = "myProp")
public class MyProperties {
private Boolean enable;
private String name;
}
- 在Configuration中導入
@Configuration
@EnableConfigurationProperties({MyProperties.class})
public class WebApiAutoConfiguration {
}
- 打包
mvn clean install
- 生產metadata.json 可以看到,在jar中的/META-INF目錄下多了一個spring-configuration-metadata.json文件
@Conditional
實現spring bean的可插拔,我們可以基于屬性、配置、類或者Bean來控制配置(@Configuration)是否生效,常見的有下面的這些:
- ConditionalOnBean 容器存在Bean時配置有效
- ConditionalOnClass classpath中有指定class時配置有效
- ConditionalOnMissingBean 容器不存在Bean時配置有效
- ConditionalOnMissingClass classpath中沒有指定class時配置有效
- ConditionalOnProperty 屬性配置對應值成立時配置有效
AutoConfigure和@Enable
AutoConfigure是在spring.factories中配置了就會加載,但是可以通過@Conditional讓配置中的Bean不生效;@Enable需要顯示地使用才能有效,且先于AutoConfigure生效,從而可以配合@Conditional來阻斷AutoConfigure的配置
結束語
關于Spring框架的學習后面會慢慢增多,我們會從原理到實踐來介紹其功能,如果你有感興趣的技術點或者開發中的問題,可以通過留言進行交流分享。
-
SPI
+關注
關注
17文章
1742瀏覽量
93782 -
緩存
+關注
關注
1文章
244瀏覽量
26942 -
數據庫
+關注
關注
7文章
3875瀏覽量
65443 -
spring
+關注
關注
0文章
340瀏覽量
14734 -
Starter
+關注
關注
0文章
8瀏覽量
7625
發布評論請先 登錄
相關推薦
Spring Boot如何實現異步任務
Spring Boot使用Tomcat作為默認的嵌入式服務器
Spring Boot嵌入式Web容器原理是什么
Spring Boot從零入門1 詳述
「Spring認證」什么是Spring GraphQL?

學習Spring Boot 嵌入式服務器

Spring Boot特有的實踐
強大的Spring Boot 3.0要來了
Spring Boot Web相關的基礎知識
簡述Spring Boot數據校驗
kafka client在 spring如何實現

Spring Boot Actuator快速入門
Spring Boot啟動 Eureka流程

Spring Boot的啟動原理

評論