spring boot@EnableXXXX注解編程模型講解
@EnableXXXX編程模型
在spring boot中,@EnableXXX注解的功能通常是開啟某一種功能。根據(jù)某些外部配置自動(dòng)裝配一些bean,來(lái)達(dá)到開啟某些功能的目的。光說(shuō)很抽象,要具體分析。
@Enable模型的實(shí)現(xiàn)方式基本有3種。一個(gè)基本的@Enable注解的模型如下。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(XXXX.class)
public @interface EnableDiscoveryClient {
/**
* If true, the ServiceRegistry will automatically register the local server.
*/
boolean autoRegister() default true;
}
對(duì)應(yīng)XXXX.class的不同,有3種實(shí)現(xiàn)方式。
- 普通配置類,里面包含@Bean方法用于實(shí)例化bean
- ImportSelector實(shí)現(xiàn)類
- ImportBeanDefinitionRegistrar實(shí)現(xiàn)類
上面3種類都屬于@Import注解的導(dǎo)入對(duì)象,整個(gè)外部化配置過(guò)程圍繞@Import注解進(jìn)行解析,導(dǎo)入類。
@Import注解處理時(shí)機(jī)節(jié)點(diǎn)(@Confguration注解的類處理)
@Import注解的處理過(guò)程大致可以描述為:
- 尋找BeanFactory中所有被@Configuration注解修飾的類,包括被@Configuration派生注解修飾的類。
- 尋找被@Configuration注解修飾的類上的所有注解元信息(這里的搜索不僅是搜索當(dāng)前注解,還會(huì)迭代往修飾注解的注解的注解上層…..一直搜索@Import,直到注解最原始的注解),獲取@Import注解的導(dǎo)入類信息,如果沒(méi)有則不處理。
- 根據(jù)導(dǎo)入類的信息,判定為
普通配置類,里面包含@Bean方法用于實(shí)例化bean
ImportSelector實(shí)現(xiàn)類
ImportBeanDefinitionRegistrar實(shí)現(xiàn)類
3種形式進(jìn)行處理。
從context啟動(dòng)開始跟蹤主線處理代碼,調(diào)用鏈條如下。
org.springframework.context.support.AbstractApplicationContext#refresh org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions(主線代碼,必看)
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//定義@Conguration注解修飾的類注冊(cè)信息列表
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
//檢查當(dāng)前context中所有的bean注冊(cè)信息
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//檢查class是否是@Conguration注解修飾的類,包括被“繼承”@Conguration注解的注解,例如@SpringBootConguration,具體可以跟蹤C(jī)onfigurationClassUtils.checkConfigurationClassCandidate實(shí)現(xiàn)
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
//對(duì)配置類排序,順序由Ordered接口決定
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
//......略略略
// Parse each @Configuration class
//處理每一個(gè)配置類
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//解析處理配置類邏輯
parser.parse(candidates);
//......略略略
}
while (!candidates.isEmpty());
//......略略略
}
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set
ImportSelector
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
返回結(jié)果是所有需要導(dǎo)入的的類的全限定名。
對(duì)于全限定名數(shù)組,逐個(gè)進(jìn)行org.springframework.context.annotation.ConfigurationClassParser#processImports,相當(dāng)于循環(huán)調(diào)用processImports,把新導(dǎo)入的類也當(dāng)做@Import導(dǎo)入的類處理,如果新導(dǎo)入的類繼續(xù)導(dǎo)入新的類,就繼續(xù)org.springframework.context.annotation.ConfigurationClassParser#processImports。直到新導(dǎo)入的類不是
ImportSelector。
ImportBeanDefinitionRegistrar處理
當(dāng)@Import的類是不是ImportSelector之后,如果是ImportBeanDefinitionRegistrar,那就做BeanDefinition信息注冊(cè)到BeanFactory操作,具體實(shí)現(xiàn)在org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions實(shí)現(xiàn),在這里的處理過(guò)程是。
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
//將ImportBeanDefinitionRegistrar放入map緩存起來(lái)
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}
先緩存@Import導(dǎo)入的ImportBeanDefinitionRegistrar信息,稍后統(tǒng)一調(diào)用ImportBeanDefinitionRegistrar加載注冊(cè)BeanDefinition信息。
@Configurtion注解的類處理
重復(fù)上面的整個(gè)流程,處理這個(gè)被@Configuration注解標(biāo)注的類。比較需要注意的是一般@Configuration注解標(biāo)注的類常用@Bean方式來(lái)實(shí)例化實(shí)例。這里#Bean也會(huì)解析出一個(gè)BeanMethod信息集合,稍后跟ImportBeanDefinitionRegistrar的緩存信息一樣統(tǒng)一調(diào)用然后注冊(cè)BeanDefinition。
// Process individual @Bean methods
//對(duì)配置類的@Bean方法處理邏輯
//獲取所有@Bean標(biāo)注的方法元信息,后續(xù)處理
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
統(tǒng)一調(diào)用配置類解析出來(lái)的信息注冊(cè)BeanDefinition
在解析完配置類之后,實(shí)際還沒(méi)有進(jìn)行BeanDefinition的注冊(cè),只得到了可以用來(lái)注冊(cè)BeanDefinition的“信息工具”,利用@Bean得到了BeanMethod,@Import(xxxImportBeanDefinitionRegistrar.class)得到了ImportBeanDefinitionRegistrar的實(shí)現(xiàn)類。最終要使用這些工具進(jìn)行BeanDefinition 信息注冊(cè)。
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions中,當(dāng)處理完@Configuration注解的類之后就進(jìn)行ImportBeanDefinitionRegistrar的BeanDefinition注冊(cè)加載。
//處理@Configuration,遞歸尋找@Configuration,以及解析@Configuration里面的@Import、@Bean、@Component、@ImportResource等。
parser.parse(candidates);
parser.validate();
//獲取parser中解析得到的所有配置類
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//根據(jù)遞歸找出的配置類和解析配置類得到的信息,加載BeanDefinition
this.reader.loadBeanDefinitions(configClasses);
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
//利用@Bean的Method加載BeanDefinition
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//利用緩存的ImportBeanDefinitionRegistrar加載注冊(cè)beandefintion
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars(以ImportBeanDefinitionRegistrar為例跟蹤) org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(注冊(cè)BeanDefinition信息到BeanFactory)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java中Buffer緩沖區(qū)的ByteBuffer類詳解
這篇文章主要介紹了Java中Buffer緩沖區(qū)的ByteBuffer類詳解,ByteBuffer類是Java NIO庫(kù)中的一個(gè)重要類,用于處理字節(jié)數(shù)據(jù),它提供了一種靈活的方式來(lái)讀取、寫入和操作字節(jié)數(shù)據(jù),ByteBuffer類是一個(gè)抽象類,可以通過(guò)靜態(tài)方法創(chuàng)建不同類型的ByteBuffer對(duì)象,需要的朋友可以參考下2023-10-10
SpringSecurity+jwt+redis基于數(shù)據(jù)庫(kù)登錄認(rèn)證的實(shí)現(xiàn)
本文主要介紹了SpringSecurity+jwt+redis基于數(shù)據(jù)庫(kù)登錄認(rèn)證的實(shí)現(xiàn),其中也涉及到自定義的過(guò)濾器和處理器,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09
SpringCloud中的路由網(wǎng)關(guān)鑒權(quán)熔斷詳解
這篇文章主要介紹了SpringCloud中的路由網(wǎng)關(guān)鑒權(quán)熔斷詳解,Hystrix是一個(gè)用于處理分布式系統(tǒng)的延遲和容錯(cuò)的開源庫(kù),在分布式系統(tǒng)里,許多依賴不可避免的會(huì)調(diào)用失敗,比如超時(shí)、異常等,需要的朋友可以參考下2024-01-01
SSH框架網(wǎng)上商城項(xiàng)目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示
SSH框架網(wǎng)上商城項(xiàng)目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示,提供了豐富的選擇、排序、分組和編輯數(shù)據(jù)的功能支持,感興趣的小伙伴們可以參考一下2016-05-05
springboot如何獲取接口下所有實(shí)現(xiàn)類
這篇文章主要介紹了springboot如何獲取接口下所有實(shí)現(xiàn)類問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
Springboot 限制IP訪問(wèn)指定的網(wǎng)址實(shí)現(xiàn)
本文主要介紹了Springboot 限制IP訪問(wèn)指定的網(wǎng)址實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05

