日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Spring Boot 中 @EnableXXX 注解的驱动逻辑探讨

發(fā)布時(shí)間:2025/3/21 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Boot 中 @EnableXXX 注解的驱动逻辑探讨 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作者 |?溫安適

來(lái)源 |?https://juejin.im/post/5efdd689e51d4534af686ca9

工作中經(jīng)常用到,如下注解:

  • @EnableEurekaClient

  • @EnableFeignClients

  • @EnableCircuitBreaker

  • @EnableHystrix

他們都是@Enable開頭,各自實(shí)現(xiàn)不同的功能,解析這種@Enable的邏輯是什么呢?

@Enable驅(qū)動(dòng)邏輯

找入口

@Enable的模塊驅(qū)動(dòng),依賴于@Import實(shí)現(xiàn)。

@Import作用是裝載導(dǎo)入類,主要包括@Configuration class,ImportSelector實(shí)現(xiàn)類,ImportBeanDefinitionRegistrar實(shí)現(xiàn)類。

XML時(shí)代,經(jīng)常是@Import,<context:component-scan>,<context:annotation-config>一起使用。

<context:annotation-config>(注解配置)中大概率有我們需要找的邏輯。

根據(jù) Spring Framework 2.0引入的可擴(kuò)展的XML編程機(jī)制,XML Schema命名空間需要與Handler建立映射關(guān)系。

該關(guān)系配置在相對(duì)于classpath下的/META-INF/spring.handlers中。

查看ContextNamespaceHandler 源碼

public?class?ContextNamespaceHandler?extends?NamespaceHandlerSupport?{@Overridepublic?void?init()?{//省略其他代碼registerBeanDefinitionParser("annotation-config",?new?AnnotationConfigBeanDefinitionParser());} }

** 對(duì)應(yīng)AnnotationConfigBeanDefinitionParser這個(gè)就是要找的入口**

找核心類

從AnnotationConfigBeanDefinitionParser的parse方法開始一路向下,找到

AnnotationConfigUtils.registerAnnotationConfigProcessors中注冊(cè)了ConfigurationClassPostProcessor。

ConfigurationClassPostProcessor類注釋說(shuō)明

\1. 用于的引導(dǎo)處理@Configuration類

\2. context:annotation-config/或 context:component-scan/時(shí)會(huì)注冊(cè)

否則需要手工編程

\3. ConfigurationClassPostProcessor第一優(yōu)先級(jí),保證

@Configuration}類中聲明@Bean,在其他 BeanFactoryPostProcessor執(zhí)行之前被注冊(cè)

擴(kuò)展

AnnotationConfigApplicationContext中new AnnotationBeanDefinitionReader也調(diào)用了?AnnotationConfigUtils .

registerAnnotationConfigProcessors

從類注釋中,可以看出ConfigurationClassPostProcessor就是要找的核心類

找核心方法

查看 ConfigurationClassPostProcessor 的層級(jí)關(guān)系為

Aware系列注入相應(yīng)資源,Ordered設(shè)置優(yōu)先級(jí),值得關(guān)注的就是

postProcessBeanDefinitionRegistry了。

postProcessBeanDefinitionRegistry其內(nèi)部有2個(gè)方法

  • postProcessBeanDefinitionRegistry在BeanDefinition注冊(cè)之后,BeanFactoryPostProcessor執(zhí)行之前,修改或重寫B(tài)eanDefinition

  • 繼承自BeanFactoryPostProcessor的postProcessBeanFactory,BeanDefinition加載之后,Bean實(shí)例化之前,重寫或添加BeanDefinition,修改BeanFactory

  • 瀏覽2個(gè)方法,都有processConfigBeanDefinitions,從名稱可以看出是處理配置類Bean定義

    ?

    ConfigurationClassPostProcessor#processConfigBeanDefinitions就是要找的核心方法

    梳理流程

    public?void?processConfigBeanDefinitions(BeanDefinitionRegistry?registry)?{List<BeanDefinitionHolder>?configCandidates?=?new?ArrayList<>();String[]?candidateNames?=?registry.getBeanDefinitionNames();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);}}else?if?(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,?this.metadataReaderFactory))?{configCandidates.add(new?BeanDefinitionHolder(beanDef,?beanName));}}//?沒有找到?@Configuration?classes?立即返回if?(configCandidates.isEmpty())?{return;}//根據(jù)@Order?值進(jìn)行排序configCandidates.sort((bd1,?bd2)?->?{int?i1?=?ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int?i2?=?ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return?Integer.compare(i1,?i2);});//通過(guò)封閉的應(yīng)用程序上下文,?檢測(cè)任何自定義bean名稱生成策略supplied?through?the?enclosing?application?contextSingletonBeanRegistry?sbr?=?null;if?(registry?instanceof?SingletonBeanRegistry)?{sbr?=?(SingletonBeanRegistry)?registry;if?(!this.localBeanNameGeneratorSet)?{BeanNameGenerator?generator?=?(BeanNameGenerator)?sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);if?(generator?!=?null)?{this.componentScanBeanNameGenerator?=?generator;this.importBeanNameGenerator?=?generator;}}}if?(this.environment?==?null)?{this.environment?=?new?StandardEnvironment();}//?解析@Configuration?classConfigurationClassParser?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);parser.validate();Set<ConfigurationClass>?configClasses?=?new?LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);//?讀ConfigurationClass的信息,創(chuàng)建BeanDefinitionif?(this.reader?==?null)?{this.reader?=?new?ConfigurationClassBeanDefinitionReader(registry,?this.sourceExtractor,?this.resourceLoader,?this.environment,this.importBeanNameGenerator,?parser.getImportRegistry());}this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);candidates.clear();if?(registry.getBeanDefinitionCount()?>?candidateNames.length)?{String[]?newCandidateNames?=?registry.getBeanDefinitionNames();Set<String>?oldCandidateNames?=?new?HashSet<>(Arrays.asList(candidateNames));Set<String>?alreadyParsedClasses?=?new?HashSet<>();for?(ConfigurationClass?configurationClass?:?alreadyParsed)?{alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for?(String?candidateName?:?newCandidateNames)?{if?(!oldCandidateNames.contains(candidateName))?{BeanDefinition?bd?=?registry.getBeanDefinition(candidateName);if?(ConfigurationClassUtils.checkConfigurationClassCandidate(bd,?this.metadataReaderFactory)?&&!alreadyParsedClasses.contains(bd.getBeanClassName()))?{candidates.add(new?BeanDefinitionHolder(bd,?candidateName));}}}candidateNames?=?newCandidateNames;}}while?(!candidates.isEmpty());//?將ImportRegistry注冊(cè)為bean以支持importware@Configuration類if?(sbr?!=?null?&&?!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME))?{sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME,?parser.getImportRegistry());}if?(this.metadataReaderFactory?instanceof?CachingMetadataReaderFactory)?{//?Clear?cache?in?externally?provided?MetadataReaderFactory;?this?is?a?no-op//?for?a?shared?cache?since?it'll?be?cleared?by?the?ApplicationContext.((CachingMetadataReaderFactory)?this.metadataReaderFactory).clearCache();} }復(fù)制代碼

    ConfigurationClassPostProcessor#processConfigBeanDefinitions核心如下:

  • 根據(jù)@Order 值進(jìn)行排序

  • 解析@Configuration class 為ConfigurationClass對(duì)象

  • 讀ConfigurationClass的信息,創(chuàng)建BeanDefinition

  • 將ImportRegistry注冊(cè)為bean以支持importware@Configuration類

  • 重點(diǎn)關(guān)注解析方法

    ConfigurationClassParser#parse方法負(fù)責(zé)解析@Configuration class 為ConfigurationClass對(duì)象

    查閱其源碼如下:

    ConfigurationClassParser#doProcessConfigurationClass代碼如下:

    protected?final?SourceClass?doProcessConfigurationClass(ConfigurationClass?configClass,?SourceClass?sourceClass)throws?IOException?{if?(configClass.getMetadata().isAnnotated(Component.class.getName()))?{//?Recursively?process?any?member?(nested)?classes?firstprocessMemberClasses(configClass,?sourceClass);}//?Process?any?@PropertySource?annotationsfor?(AnnotationAttributes?propertySource?:?AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(),?PropertySources.class,org.springframework.context.annotation.PropertySource.class))?{if?(this.environment?instanceof?ConfigurableEnvironment)?{processPropertySource(propertySource);}else?{logger.info("Ignoring?@PropertySource?annotation?on?["?+?sourceClass.getMetadata().getClassName()?+"].?Reason:?Environment?must?implement?ConfigurableEnvironment");}}//?Process?any?@ComponentScan?annotationsSet<AnnotationAttributes>?componentScans?=?AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(),?ComponentScans.class,?ComponentScan.class);if?(!componentScans.isEmpty()?&&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),?ConfigurationPhase.REGISTER_BEAN))?{for?(AnnotationAttributes?componentScan?:?componentScans)?{//?The?config?class?is?annotated?with?@ComponentScan?->?perform?the?scan?immediatelySet<BeanDefinitionHolder>?scannedBeanDefinitions?=this.componentScanParser.parse(componentScan,?sourceClass.getMetadata().getClassName());//?Check?the?set?of?scanned?definitions?for?any?further?config?classes?and?parse?recursively?if?neededfor?(BeanDefinitionHolder?holder?:?scannedBeanDefinitions)?{BeanDefinition?bdCand?=?holder.getBeanDefinition().getOriginatingBeanDefinition();if?(bdCand?==?null)?{bdCand?=?holder.getBeanDefinition();}if?(ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand,?this.metadataReaderFactory))?{parse(bdCand.getBeanClassName(),?holder.getBeanName());}}}}//?Process?any?@Import?annotationsprocessImports(configClass,?sourceClass,?getImports(sourceClass),?true);//?Process?any?@ImportResource?annotationsAnnotationAttributes?importResource?=AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(),?ImportResource.class);if?(importResource?!=?null)?{String[]?resources?=?importResource.getStringArray("locations");Class<??extends?BeanDefinitionReader>?readerClass?=?importResource.getClass("reader");for?(String?resource?:?resources)?{String?resolvedResource?=?this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource,?readerClass);}}//?Process?individual?@Bean?methodsSet<MethodMetadata>?beanMethods?=?retrieveBeanMethodMetadata(sourceClass);for?(MethodMetadata?methodMetadata?:?beanMethods)?{configClass.addBeanMethod(new?BeanMethod(methodMetadata,?configClass));}//?Process?default?methods?on?interfacesprocessInterfaces(configClass,?sourceClass);//?Process?superclass,?if?anyif?(sourceClass.getMetadata().hasSuperClass())?{String?superclass?=?sourceClass.getMetadata().getSuperClassName();if?(superclass?!=?null?&&?!superclass.startsWith("java")?&&!this.knownSuperclasses.containsKey(superclass))?{this.knownSuperclasses.put(superclass,?configClass);//?Superclass?found,?return?its?annotation?metadata?and?recursereturn?sourceClass.getSuperClass();}}//?No?superclass?->?processing?is?completereturn?null; }復(fù)制代碼

    ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass,AnnatationMetatdata)將@PropertySource, ??@ComponentScan,?@Import,@ImportResource,@Bean等一起處理了。

    看到這里基本邏輯已經(jīng)理清 了,但是有一個(gè)疑問(wèn)

    @Configuration中的@Bean沒有其他特殊處理嗎?

    瀏覽代碼解決疑問(wèn)

    ![img](data:image/svg+xml;utf8,)

    從上邊瀏覽的代碼可以看到完全模式,會(huì)被AOP增強(qiáng)

    那什么是完全模式呢?在ConfigurationClassUtils找到如下方法:

    public?class?ConfigurationClassUtils{ //省略其他方法 public?static?boolean?isFullConfigurationCandidate(AnnotationMetadata?metadata)?{return?metadata.isAnnotated(Configuration.class.getName()); } }復(fù)制代碼

    即?@Configuration class是完全模式,@Component,@Bean是輕量級(jí)模式

    那AOP增強(qiáng)了作用是什么呢?查看 ConfigurationClassEnhancer 的類注釋如下:

    /**

    * Enhances {@link

    Configuration

    } classes by generating a CGLIB subclass which

    * interacts with the Spring container to respect bean scoping semantics for

    * {@code @Bean} methods. Each such {@code @Bean} method will be overridden in

    * the generated subclass, only delegating to the actual {@code @Bean} method

    * implementation if the container actually requests the construction of a new

    * instance. Otherwise, a call to such an {@code @Bean} method serves as a

    * reference back to the container, obtaining the corresponding bean by name.

    • ?

    * @author Chris Beams

    * @author Juergen Hoeller

    * @since 3.0

    * @see #enhance

    * @see

    ConfigurationClassPostProcessor

    */

    class ?ConfigurationClassEnhancer ?{

    大概意思如下:

    通過(guò)CGLIB增強(qiáng)@Configuration class。

    每個(gè)@Bean方法會(huì)生成子類。

    首次被調(diào)用時(shí),@Bean方法會(huì)被執(zhí)行用于創(chuàng)建bean實(shí)例;

    再次被調(diào)用時(shí),不會(huì)再執(zhí)行創(chuàng)建bean實(shí)例,而是根據(jù)bean名稱返回首次該方法被執(zhí)行時(shí)創(chuàng)建的bean實(shí)例。

    總結(jié)

    1.ConfigurationClassPostProcessor負(fù)責(zé)篩選@Component Class、@Configuration Class以及@Bean定義的Bean,**

    2.ConfigurationClassParser從候選的Bean定義中解析出ConfigurationClass集合,隨后被3.ConfigurationClassBeanDefinitionReader轉(zhuǎn)換為BeanDefinition

    4.ConfigurationClassParser的解析順序,

    @PropertySource->@ComponentScan->@Import->@ImportResource->@Bean->接口的默認(rèn)方法->處理父類

    5.@Configuration class是完全模式,@Component,@Bean是輕量級(jí)模式

    6.CGLIB增強(qiáng)@Configuration class。每個(gè)@Bean方法會(huì)生成子類。

    首次被調(diào)用時(shí),@Bean方法會(huì)被執(zhí)行用于創(chuàng)建bean實(shí)例;

    再次被調(diào)用時(shí),不會(huì)再執(zhí)行創(chuàng)建bean實(shí)例,而是根據(jù)bean名稱返回首次該方法被執(zhí)行時(shí)創(chuàng)建的bean實(shí)例。

    總結(jié)

    以上是生活随笔為你收集整理的Spring Boot 中 @EnableXXX 注解的驱动逻辑探讨的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。