@EnableXXXX編程模型
在spring boot中,@EnableXXX注解的功能通常是開啟某一種功能。根據(jù)某些外部配置自動裝配一些bean,來達(dá)到開啟某些功能的目的。光說很抽象,要具體分析。
@Enable模型的實現(xiàn)方式基本有3種。一個基本的@Enable注解的模型如下。
1
2
3
4
5
6
7
8
9
10
11
|
@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 ; } |
對應(yīng)XXXX.class的不同,有3種實現(xiàn)方式。
- 普通配置類,里面包含@Bean方法用于實例化bean
- ImportSelector實現(xiàn)類
- ImportBeanDefinitionRegistrar實現(xiàn)類
上面3種類都屬于@Import注解的導(dǎo)入對象,整個外部化配置過程圍繞@Import注解進(jìn)行解析,導(dǎo)入類。
@Import注解處理時機節(jié)點(@Confguration注解的類處理)
@Import注解的處理過程大致可以描述為:
- 尋找BeanFactory中所有被@Configuration注解修飾的類,包括被@Configuration派生注解修飾的類。
- 尋找被@Configuration注解修飾的類上的所有注解元信息(這里的搜索不僅是搜索當(dāng)前注解,還會迭代往修飾注解的注解的注解上層…..一直搜索@Import,直到注解最原始的注解),獲取@Import注解的導(dǎo)入類信息,如果沒有則不處理。
- 根據(jù)導(dǎo)入類的信息,判定為
普通配置類,里面包含@Bean方法用于實例化bean
ImportSelector實現(xiàn)類
ImportBeanDefinitionRegistrar實現(xiàn)類
3種形式進(jìn)行處理。
從context啟動開始跟蹤主線處理代碼,調(diào)用鏈條如下。
1
2
3
4
|
org.springframework.context.support.AbstractApplicationContext#refresh org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions(主線代碼,必看) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { //定義@Conguration注解修飾的類注冊信息列表 List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames(); //檢查當(dāng)前context中所有的bean注冊信息 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,具體可以跟蹤ConfigurationClassUtils.checkConfigurationClassCandidate實現(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 //對配置類排序,順序由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 //處理每一個配置類 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()); //......略略略 } |
1
|
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set |
ImportSelector
1
|
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); |
返回結(jié)果是所有需要導(dǎo)入的的類的全限定名。
對于全限定名數(shù)組,逐個進(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信息注冊到BeanFactory操作,具體實現(xiàn)在org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions實現(xiàn),在這里的處理過程是。
1
2
3
4
5
6
7
8
9
10
11
|
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緩存起來 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } |
1
2
3
|
public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) { this .importBeanDefinitionRegistrars.put(registrar, importingClassMetadata); } |
先緩存@Import導(dǎo)入的ImportBeanDefinitionRegistrar信息,稍后統(tǒng)一調(diào)用ImportBeanDefinitionRegistrar加載注冊BeanDefinition信息。
@Configurtion注解的類處理
重復(fù)上面的整個流程,處理這個被@Configuration注解標(biāo)注的類。比較需要注意的是一般@Configuration注解標(biāo)注的類常用@Bean方式來實例化實例。這里#Bean也會解析出一個BeanMethod信息集合,稍后跟ImportBeanDefinitionRegistrar的緩存信息一樣統(tǒng)一調(diào)用然后注冊BeanDefinition。
1
2
3
4
5
6
7
|
// Process individual @Bean methods //對配置類的@Bean方法處理邏輯 //獲取所有@Bean標(biāo)注的方法元信息,后續(xù)處理 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod( new BeanMethod(methodMetadata, configClass)); } |
統(tǒng)一調(diào)用配置類解析出來的信息注冊BeanDefinition
在解析完配置類之后,實際還沒有進(jìn)行BeanDefinition的注冊,只得到了可以用來注冊BeanDefinition的“信息工具”,利用@Bean得到了BeanMethod,@Import(xxxImportBeanDefinitionRegistrar.class)得到了ImportBeanDefinitionRegistrar的實現(xiàn)類。最終要使用這些工具進(jìn)行BeanDefinition 信息注冊。
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions中,當(dāng)處理完@Configuration注解的類之后就進(jìn)行ImportBeanDefinitionRegistrar的BeanDefinition注冊加載。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//處理@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); |
1
2
|
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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加載注冊beandefintion loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); } |
1
2
|
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars(以ImportBeanDefinitionRegistrar為例跟蹤) org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(注冊BeanDefinition信息到BeanFactory) |
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/qq_20597727/article/details/82713267