1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Spring Boot 中 @EnableXXX 注解的驅(qū)動(dòng)邏輯

        共 12207字,需瀏覽 25分鐘

         ·

        2020-08-22 18:04

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


        • @EnableEurekaClient

        • @EnableFeignClients

        • @EnableCircuitBreaker

        • @EnableHystrix


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


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


        找入口


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


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


        XML時(shí)代,經(jīng)常是@Import,,一起使用。


        (注解配置)中大概率有我們需要找的邏輯。


        根據(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?{
        ???@Override
        ???public?void?init()?{
        ???????//省略其他代碼
        ????registerBeanDefinitionParser("annotation-config",?
        ????????????????????new?AnnotationConfigBeanDefinitionParser());
        ??}
        }復(fù)制代碼


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


        找核心類(lèi)


        從AnnotationConfigBeanDefinitionParser的parse方法開(kāi)始一路向下,找到AnnotationConfigUtils.registerAnnotationConfigProcessors中注冊(cè)了ConfigurationClassPostProcessor。



        ConfigurationClassPostProcessor類(lèi)注釋說(shuō)明


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

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

        否則需要手工編程

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

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

        擴(kuò)展

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

        registerAnnotationConfigProcessors


        從類(lèi)注釋中,可以看出ConfigurationClassPostProcessor就是要找的核心類(lèi)


        找核心方法


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


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

        postProcessBeanDefinitionRegistry了。


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


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

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


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



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


        梳理流程


        public?void?processConfigBeanDefinitions(BeanDefinitionRegistry?registry)?{
        ???List?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));
        ??????}
        ???}

        ???//?沒(méi)有找到?@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名稱(chēng)生成策略
        ???supplied?through?the?enclosing?application?context
        ???SingletonBeanRegistry?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?class
        ???ConfigurationClassParser?parser?=?new?ConfigurationClassParser(
        ?????????this.metadataReaderFactory,?this.problemReporter,?this.environment,
        ?????????this.resourceLoader,?this.componentScanBeanNameGenerator,?registry);

        ???Set?candidates?=?new?LinkedHashSet<>(configCandidates);
        ???Set?alreadyParsed?=?new?HashSet<>(configCandidates.size());
        ???do?{
        ??????parser.parse(candidates);
        ??????parser.validate();

        ??????Set?configClasses?=?new?LinkedHashSet<>(parser.getConfigurationClasses());
        ??????configClasses.removeAll(alreadyParsed);
        ??????//?讀ConfigurationClass的信息,創(chuàng)建BeanDefinition
        ??????if?(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?oldCandidateNames?=?new?HashSet<>(Arrays.asList(candidateNames));
        ?????????Set?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類(lèi)
        ???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核心如下:


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

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

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

        4. 將ImportRegistry注冊(cè)為bean以支持importware@Configuration類(lèi)


        重點(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?first
        ??????processMemberClasses(configClass,?sourceClass);
        ???}

        ???//?Process?any?@PropertySource?annotations
        ???for?(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?annotations
        ???Set?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?immediately
        ?????????Set?scannedBeanDefinitions?=
        ???????????????this.componentScanParser.parse(componentScan,?sourceClass.getMetadata().getClassName());
        ?????????//?Check?the?set?of?scanned?definitions?for?any?further?config?classes?and?parse?recursively?if?needed
        ?????????for?(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?annotations
        ???processImports(configClass,?sourceClass,?getImports(sourceClass),?true);

        ???//?Process?any?@ImportResource?annotations
        ???AnnotationAttributes?importResource?=
        ?????????AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(),?ImportResource.class);
        ???if?(importResource?!=?null)?{
        ??????String[]?resources?=?importResource.getStringArray("locations");
        ??????Class?readerClass?=?importResource.getClass("reader");
        ??????for?(String?resource?:?resources)?{
        ?????????String?resolvedResource?=?this.environment.resolveRequiredPlaceholders(resource);
        ?????????configClass.addImportedResource(resolvedResource,?readerClass);
        ??????}
        ???}

        ???//?Process?individual?@Bean?methods
        ???Set?beanMethods?=?retrieveBeanMethodMetadata(sourceClass);
        ???for?(MethodMetadata?methodMetadata?:?beanMethods)?{
        ??????configClass.addBeanMethod(new?BeanMethod(methodMetadata,?configClass));
        ???}

        ???//?Process?default?methods?on?interfaces
        ???processInterfaces(configClass,?sourceClass);

        ???//?Process?superclass,?if?any
        ???if?(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?recurse
        ?????????return?sourceClass.getSuperClass();
        ??????}
        ???}

        ???//?No?superclass?->?processing?is?complete
        ???return?null;
        }復(fù)制代碼


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


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

        @Configuration中的@Bean沒(méi)有其他特殊處理嗎?


        瀏覽代碼解決疑問(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 的類(lèi)注釋如下:

        /**

        * 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ì)生成子類(lèi)。


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


          再次被調(diào)用時(shí),不會(huì)再執(zhí)行創(chuàng)建bean實(shí)例,而是根據(jù)bean名稱(chēng)返回首次該方法被執(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)方法->處理父類(lèi)


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


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


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


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

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          1. <strong id="7actg"></strong>
          2. <table id="7actg"></table>

          3. <address id="7actg"></address>
            <address id="7actg"></address>
            1. <object id="7actg"><tt id="7actg"></tt></object>
              熟女北条麻妃在线播放 | 狠狠色噜噜狠狠狠狠色综合久老司机 | 国产精品主播一区二区 | 色秘 乱码一区二区三区在 | 久久久久久久久久久久久女国产乱 | 国产成人久久精 | 综合色站导航 | 久久精品无码日韩国产不卡 | 污污网站观看 | 少妇下面好紧好爽好多水 |