<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Springboot中@Import的使用原理

          共 3071字,需瀏覽 7分鐘

           ·

          2020-11-19 18:31

          點擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

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

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

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

          再看源碼之前先寫一個小的demo,試著看看@Import是怎么用的。(為避免文章過長,下面代碼均有一定程度的代碼刪減,可以自行補(bǔ)全或查看源碼哦?。?/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,運(yùn)行結(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()方法進(jìn)入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());
          }?

          到此再點擊進(jìn)入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()方法進(jìn)入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()方法進(jìn)入org.springframework.context.annotation.ConfigurationClassParser類當(dāng)中;

          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注解導(dǎo)入的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é)了,加個最近覺得很有道理的一句話,學(xué)習(xí)其實是個低成本,高回報的方式。



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

          本文鏈接:

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





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

          ???

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



          感謝點贊支持下哈?

          瀏覽 62
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码AV中文字幕 | 婷婷五月天婷婷五月天婷婷五月天色 | 欧美成人精品a | 中文永久免费观看 | 久草热人妻 |