最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring boot@EnableXXXX注解編程模型講解

 更新時(shí)間:2021年09月28日 10:29:01   作者:一擼向北  
這篇文章主要介紹了spring boot@EnableXXXX注解編程模型,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

@EnableXXXX編程模型

在spring boot中,@EnableXXX注解的功能通常是開(kāi)啟某一種功能。根據(jù)某些外部配置自動(dòng)裝配一些bean,來(lái)達(dá)到開(kāi)啟某些功能的目的。光說(shuō)很抽象,要具體分析。

@Enable模型的實(shí)現(xiàn)方式基本有3種。一個(gè)基本的@Enable注解的模型如下。

@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;
}

對(duì)應(yīng)XXXX.class的不同,有3種實(shí)現(xiàn)方式。

  • 普通配置類(lèi),里面包含@Bean方法用于實(shí)例化bean
  • ImportSelector實(shí)現(xiàn)類(lèi)
  • ImportBeanDefinitionRegistrar實(shí)現(xiàn)類(lèi)

上面3種類(lèi)都屬于@Import注解的導(dǎo)入對(duì)象,整個(gè)外部化配置過(guò)程圍繞@Import注解進(jìn)行解析,導(dǎo)入類(lèi)。

@Import注解處理時(shí)機(jī)節(jié)點(diǎn)(@Confguration注解的類(lèi)處理)

@Import注解的處理過(guò)程大致可以描述為:

  • 尋找BeanFactory中所有被@Configuration注解修飾的類(lèi),包括被@Configuration派生注解修飾的類(lèi)。
  • 尋找被@Configuration注解修飾的類(lèi)上的所有注解元信息(這里的搜索不僅是搜索當(dāng)前注解,還會(huì)迭代往修飾注解的注解的注解上層…..一直搜索@Import,直到注解最原始的注解),獲取@Import注解的導(dǎo)入類(lèi)信息,如果沒(méi)有則不處理。
  • 根據(jù)導(dǎo)入類(lèi)的信息,判定為

普通配置類(lèi),里面包含@Bean方法用于實(shí)例化bean

ImportSelector實(shí)現(xiàn)類(lèi)

ImportBeanDefinitionRegistrar實(shí)現(xiàn)類(lèi)

3種形式進(jìn)行處理。

從context啟動(dòng)開(kāi)始跟蹤主線處理代碼,調(diào)用鏈條如下。

org.springframework.context.support.AbstractApplicationContext#refresh
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions(主線代碼,必看)
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  //定義@Conguration注解修飾的類(lèi)注冊(cè)信息列表
 List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
 String[] candidateNames = registry.getBeanDefinitionNames();
//檢查當(dāng)前context中所有的bean注冊(cè)信息
 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注解修飾的類(lèi),包括被“繼承”@Conguration注解的注解,例如@SpringBootConguration,具體可以跟蹤C(jī)onfigurationClassUtils.checkConfigurationClassCandidate實(shí)現(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
  //對(duì)配置類(lèi)排序,順序由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
  //處理每一個(gè)配置類(lèi)
 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 {
     //解析處理配置類(lèi)邏輯
    parser.parse(candidates);
     //......略略略
 }
 while (!candidates.isEmpty());
//......略略略
}
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set

ImportSelector

String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());

返回結(jié)果是所有需要導(dǎo)入的的類(lèi)的全限定名。

對(duì)于全限定名數(shù)組,逐個(gè)進(jìn)行org.springframework.context.annotation.ConfigurationClassParser#processImports,相當(dāng)于循環(huán)調(diào)用processImports,把新導(dǎo)入的類(lèi)也當(dāng)做@Import導(dǎo)入的類(lèi)處理,如果新導(dǎo)入的類(lèi)繼續(xù)導(dǎo)入新的類(lèi),就繼續(xù)org.springframework.context.annotation.ConfigurationClassParser#processImports。直到新導(dǎo)入的類(lèi)不是

ImportSelector。

ImportBeanDefinitionRegistrar處理

當(dāng)@Import的類(lèi)是不是ImportSelector之后,如果是ImportBeanDefinitionRegistrar,那就做BeanDefinition信息注冊(cè)到BeanFactory操作,具體實(shí)現(xiàn)在org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions實(shí)現(xiàn),在這里的處理過(guò)程是。

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緩存起來(lái)
   configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
   this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}

先緩存@Import導(dǎo)入的ImportBeanDefinitionRegistrar信息,稍后統(tǒng)一調(diào)用ImportBeanDefinitionRegistrar加載注冊(cè)BeanDefinition信息。

@Configurtion注解的類(lèi)處理

重復(fù)上面的整個(gè)流程,處理這個(gè)被@Configuration注解標(biāo)注的類(lèi)。比較需要注意的是一般@Configuration注解標(biāo)注的類(lèi)常用@Bean方式來(lái)實(shí)例化實(shí)例。這里#Bean也會(huì)解析出一個(gè)BeanMethod信息集合,稍后跟ImportBeanDefinitionRegistrar的緩存信息一樣統(tǒng)一調(diào)用然后注冊(cè)BeanDefinition。

// Process individual @Bean methods
//對(duì)配置類(lèi)的@Bean方法處理邏輯
//獲取所有@Bean標(biāo)注的方法元信息,后續(xù)處理
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
   configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

統(tǒng)一調(diào)用配置類(lèi)解析出來(lái)的信息注冊(cè)BeanDefinition

在解析完配置類(lèi)之后,實(shí)際還沒(méi)有進(jìn)行BeanDefinition的注冊(cè),只得到了可以用來(lái)注冊(cè)BeanDefinition的“信息工具”,利用@Bean得到了BeanMethod,@Import(xxxImportBeanDefinitionRegistrar.class)得到了ImportBeanDefinitionRegistrar的實(shí)現(xiàn)類(lèi)。最終要使用這些工具進(jìn)行BeanDefinition 信息注冊(cè)。

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions中,當(dāng)處理完@Configuration注解的類(lèi)之后就進(jìn)行ImportBeanDefinitionRegistrar的BeanDefinition注冊(cè)加載。

//處理@Configuration,遞歸尋找@Configuration,以及解析@Configuration里面的@Import、@Bean、@Component、@ImportResource等。
parser.parse(candidates);
parser.validate();
//獲取parser中解析得到的所有配置類(lèi)
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ù)遞歸找出的配置類(lèi)和解析配置類(lèi)得到的信息,加載BeanDefinition
this.reader.loadBeanDefinitions(configClasses);
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
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加載注冊(cè)beandefintion
   loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars(以ImportBeanDefinitionRegistrar為例跟蹤)
org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(注冊(cè)BeanDefinition信息到BeanFactory)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 注冊(cè)中心配置了spring?security后客戶(hù)端啟動(dòng)報(bào)錯(cuò)

    注冊(cè)中心配置了spring?security后客戶(hù)端啟動(dòng)報(bào)錯(cuò)

    這篇文章主要為大家介紹了注冊(cè)中心配置了spring?security后客戶(hù)端啟動(dòng)報(bào)錯(cuò)問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • java集合類(lèi)HashMap源碼解析

    java集合類(lèi)HashMap源碼解析

    這篇文章主要介紹了Java集合之HashMap用法,結(jié)合實(shí)例形式分析了java map集合中HashMap定義、遍歷等相關(guān)操作技巧,需要的朋友可以參考下
    2021-06-06
  • SpringBoot打包后無(wú)法讀取到resource下的資源文件的解決

    SpringBoot打包后無(wú)法讀取到resource下的資源文件的解決

    這篇文章主要介紹了SpringBoot打包后無(wú)法讀取到resource下的資源文件的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • 使用JDBC連接Mysql 8.0.11出現(xiàn)了各種錯(cuò)誤的解決

    使用JDBC連接Mysql 8.0.11出現(xiàn)了各種錯(cuò)誤的解決

    這篇文章主要介紹了使用JDBC連接Mysql 8.0.11出現(xiàn)了各種錯(cuò)誤的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • SpringBoot整合Mysql和Redis的詳細(xì)過(guò)程

    SpringBoot整合Mysql和Redis的詳細(xì)過(guò)程

    這篇文章主要介紹了SpringBoot整合Mysql和Redis的示例代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • 新手了解java 數(shù)組基礎(chǔ)知識(shí)

    新手了解java 數(shù)組基礎(chǔ)知識(shí)

    這篇文章主要介紹了Java 數(shù)組分析及簡(jiǎn)單實(shí)例的相關(guān)資料,在Java中它就是對(duì)象,一個(gè)比較特殊的對(duì)象,需要的朋友可以參考下,希望可以對(duì)你有所幫助
    2021-07-07
  • SpringBoot+MDC實(shí)現(xiàn)鏈路調(diào)用日志的方法

    SpringBoot+MDC實(shí)現(xiàn)鏈路調(diào)用日志的方法

    MDC是 log4j 、logback及l(fā)og4j2 提供的一種方便在多線程條件下記錄日志的功能,這篇文章主要介紹了SpringBoot+MDC實(shí)現(xiàn)鏈路調(diào)用日志,需要的朋友可以參考下
    2022-12-12
  • Java實(shí)現(xiàn)并查集

    Java實(shí)現(xiàn)并查集

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)并查集,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • Java中final作用于變量、參數(shù)、方法及類(lèi)該如何處理

    Java中final作用于變量、參數(shù)、方法及類(lèi)該如何處理

    Java中的final關(guān)鍵字非常重要,它可以應(yīng)用于類(lèi)、方法以及變量,下面這篇文章主要給大家介紹了關(guān)于Java中final作用于變量、參數(shù)、方法及類(lèi)該如何處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。
    2017-12-12
  • Java?IO流之StringWriter和StringReader用法分析

    Java?IO流之StringWriter和StringReader用法分析

    這篇文章主要介紹了Java?IO流之StringWriter和StringReader用法分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評(píng)論

平顺县| 高邮市| 定远县| 达州市| 兖州市| 贵溪市| 资源县| 裕民县| 胶南市| 中山市| 德格县| 阿克苏市| 祁阳县| 纳雍县| 广南县| 贵阳市| 兴业县| 金坛市| 镇沅| 莆田市| 灌阳县| 宁阳县| 安图县| 青河县| 老河口市| 清远市| 京山县| 乐陵市| 铁岭市| 五指山市| 无锡市| 岳池县| 华亭县| 喀什市| 区。| 邛崃市| 山东| 农安县| 忻城县| 松江区| 霞浦县|