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>

        Springboot中@Import的使用原理

        共 3071字,需瀏覽 7分鐘

         ·

        2020-11-19 18:31

        點擊上方藍色字體,選擇“標星公眾號”

        優(yōu)質(zhì)文章,第一時間送達

        66套java從入門到精通實戰(zhàn)課程分享

        最近我看了看Springboot的源碼,借著周末分享@Import這一小知識點,也正好體驗一下CSDN博客最新的編輯器。編輯起來很好用,舒服。

        再看源碼之前先寫一個小的demo,試著看看@Import是怎么用的。(為避免文章過長,下面代碼均有一定程度的代碼刪減,可以自行補全或查看源碼哦?。?/span>

        1.創(chuàng)建一個maven項目,pom.xml文件配置如下:


        ??org.springframework.boot
        ??spring-boot-starter-parent
        ??1.5.6.RELEASE
        ?

        ?
        ??
        ???org.springframework.boot
        ???spring-boot-starter-web
        ??

        ?

        ?
        ??
        ???
        ????org.springframework.boot
        ????spring-boot-maven-plugin
        ???

        ??

        ?


        2.創(chuàng)建一個實體類

        package?com.entity;
        ?
        public?class?User?implements?Serializable{
        ?
        ?private?String?name;
        ?private?String?age;
        ?
        ?public?User()?{
        ??this.name?=?"xiaochen";
        ??this.age?=?"6";
        ?}
        }

        3.創(chuàng)建ImportUser類

        package?com.demo;
        ?
        public?class?ImportUser?implements?ImportSelector?{
        ?@Override
        ?public?String[]?selectImports(AnnotationMetadata?importingClassMetadata)?{
        ??return?new?String[]?{"com.entity.User"};
        ?}
        }

        這里看到ImportSelector接口,是不是好像在哪里見過呢?

        4.創(chuàng)建配置類

        package?com.demo;
        ?
        @Import(ImportUser.class)
        @Configuration
        public?class?ImportConfiguration?{}

        5.創(chuàng)建啟動類

        package?com.demo;
        public?class?ImportDemo?{
        ?public?static?void?main(String[]?args)?{
        ??AnnotationConfigApplicationContext?applicationContext?=?new?AnnotationConfigApplicationContext();
        //這里使用register()和scan()方法都可,用scan()方法就不用在配置類中使用@Configuration注解了。
        //??applicationContext.register(ImportConfiguration.class);
        ??applicationContext.scan("com.demo");
        ??applicationContext.refresh();
        ??User?user?=?applicationContext.getBean(User.class);
        ?????System.out.println(user);
        ?}
        }

        6,運行結(jié)果

        上邊的代碼很簡單,就不過多解釋,下面直接看Springboot中是怎么使用的。

        我們知道@SpringbootApplication注解主要是由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan組成。而@EnableAutoConfiguration中就用到了@Import注解,用于引入

        EnableAutoConfigurationImportSelector類,代碼如下:

        @Import(EnableAutoConfigurationImportSelector.class)
        public?@interface?EnableAutoConfiguration?{}

        ?這里我們先創(chuàng)建一個Springboot啟動類

        @SpringBootApplication
        public?class?ApplicationStart?{
        ?public?static?void?main(String[]?args)?{
        ??SpringApplication.run(ApplicationStart.class,?args);
        ?}
        }

        ?點擊run()方法進入SpringApplication類中,依次查看調(diào)用方法;

        public?ConfigurableApplicationContext?run(String...?args)?{
        ???refreshContext(context);
        }
        private?void?refreshContext(ConfigurableApplicationContext?context)?{
        ??refresh(context);
        }
        protected?void?refresh(ApplicationContext?applicationContext)?{
        ??((AbstractApplicationContext)?applicationContext).refresh();
        }
        ?
        @Override
        public?void?refresh()?throws?BeansException,?IllegalStateException?{
        ??invokeBeanFactoryPostProcessors(beanFactory);
        }
        ?
        protected?void?invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory?beanFactory)?{
        ?????PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,?getBeanFactoryPostProcessors());
        }?

        到此再點擊進入org.springframework.context.support.PostProcessorRegistrationDelegate類中;

        public?static?void?invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory?beanFactory,?List?beanFactoryPostProcessors)?{
        ?????invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors,?registry);
        }
        ?
        private?static?void?invokeBeanDefinitionRegistryPostProcessors(
        ???Collection?postProcessors,?BeanDefinitionRegistry?registry)?{
        ?for?(BeanDefinitionRegistryPostProcessor?postProcessor?:?postProcessors)?{
        ???postProcessor.postProcessBeanDefinitionRegistry(registry);
        ?}
        }

        再點擊postProcessBeanDefinitionRegistry()方法進入org.springframework.context.annotation.ConfigurationClassPostProcessor類中;

        public?void?postProcessBeanDefinitionRegistry(BeanDefinitionRegistry?registry)?{
        ??processConfigBeanDefinitions(registry);
        }
        ?
        public?void?processConfigBeanDefinitions(BeanDefinitionRegistry?registry)?{
        //?Parse?each?@Configuration?class
        ?ConfigurationClassParser?parser?=?new?ConfigurationClassParser(
        ????this.metadataReaderFactory,?this.problemReporter,?this.environment,
        ????this.resourceLoader,?this.componentScanBeanNameGenerator,?registry);
        ?????parser.parse(candidates);
        }

        這里再點擊parse()方法進入org.springframework.context.annotation.ConfigurationClassParser類當中;

        public?void?parse(Set?configCandidates)?{
        ??processDeferredImportSelectors();
        }
        private?void?processDeferredImportSelectors()?{
        ????????String[]?imports?=?deferredImport.getImportSelector().selectImports(configClass.getMetadata());
        ????????processImports(configClass,?asSourceClass(configClass),?asSourceClasses(imports),?false);
        }

        這里看到selectImports()方法就在上面demo中出現(xiàn)過,再查看一下之前使用@Import注解導入的EnableAutoConfigurationImportSelector類,其就間接實現(xiàn)了ImportSelector接口;這和demo中是不是很相似。

        這里的?selectImports()方法再往里就是讀取各個jar包中有含?META-INF/spring.factories.文件的信息了,這里就不多做分析了。

        但這里會不會有個疑問,@Import是怎么起作用的,這里就要看看deferredImport是怎么實例化的?。?!,也是在上面的方法中有這樣一段代碼;

        private?void?processDeferredImportSelectors()?{
        List?deferredImports?=?this.deferredImportSelectors;
        this.deferredImportSelectors?=?null;
        Collections.sort(deferredImports,?DEFERRED_IMPORT_COMPARATOR);
        for?(DeferredImportSelectorHolder?deferredImport?:?deferredImports)?{
        ?ConfigurationClass?configClass?=?deferredImport.getConfigurationClass();
        }
        }

        代碼中可以看出是deferredImportSelectors對象間接賦值?, 那就找它實例化的位置;

        private?void?processImports(ConfigurationClass?configClass,?SourceClass?currentSourceClass,Collection?importCandidates,
        ???????boolean?checkForCircularImports)?throws?IOException?{
        ????for?(SourceClass?candidate?:?importCandidates)?{
        ??if?(candidate.isAssignable(ImportSelector.class))?{
        //?Candidate?class?is?an?ImportSelector?->?delegate?to?it?to?determine?imports
        ?????Class?candidateClass?=?candidate.loadClass();
        ????????????//這里用于實例化ImportSelector的實現(xiàn)類
        ?????ImportSelector?selector?=?BeanUtils.instantiateClass(candidateClass,ImportSelector.class);
        ?????ParserStrategyUtils.invokeAwareMethods(selector,?this.environment,this.resourceLoader,?this.registry);
        ?????if?(this.deferredImportSelectors?!=?null?&&?selector?instanceof?DeferredImportSelector)?{
        ????this.deferredImportSelectors.add(new?DeferredImportSelectorHolder(configClass,?(DeferredImportSelector)?selector));
        ???}??
        ?????}
        ????}
        }

        上面也就是判斷并實例化ImportSelector接口的實現(xiàn)類,而怎么識別的呢? importCandidates又是如何得到的?接著找。。

        protected?final?SourceClass?doProcessConfigurationClass(ConfigurationClass?configClass,?SourceClass?sourceClass)?throws?IOException?{
        //?Process?any?@Import?annotations
        ?processImports(configClass,?sourceClass,?getImports(sourceClass),?true);
        }
        private?Set?getImports(SourceClass?sourceClass)?throws?IOException?{
        ??Set?imports?=?new?LinkedHashSet();
        ??Set?visited?=?new?LinkedHashSet();
        ??collectImports(sourceClass,?imports,?visited);
        ??return?imports;
        }
        private?void?collectImports(SourceClass?sourceClass,?Set?imports,Set?visited)?throws?IOException?{
        ?if?(visited.add(sourceClass))?{
        ??for?(SourceClass?annotation?:?sourceClass.getAnnotations())?{
        ???String?annName?=?annotation.getMetadata().getClassName();
        ???if?(!annName.startsWith("java")?&&?!annName.equals(Import.class.getName()))?{
        ????collectImports(annotation,?imports,?visited);
        ???}
        ??}
        ????????imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(),?"value"));
        ?}
        }

        看到這里的判斷也大體明白了吧。

        這里就不做總結(jié)了,加個最近覺得很有道理的一句話,學習其實是個低成本,高回報的方式。



        版權聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。

        本文鏈接:

        https://blog.csdn.net/qq_21299835/article/details/109695279





        粉絲福利:實戰(zhàn)springboot+CAS單點登錄系統(tǒng)視頻教程免費領取

        ???

        ?長按上方微信二維碼?2 秒
        即可獲取資料



        感謝點贊支持下哈?

        瀏覽 62
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        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>
            欧美黑鸡巴 | 在线 无码| 超碰不卡| 公交车激情小说h | 国产精品欧美一区二区 | 91麻豆国产福利精品精华液 | 国产一级a毛一级a看免费视频黑人 | 真人看一级毛片 | 中文字幕一区二区二区三级片 | 看A片在线 |