• spring源码之@Import


    @Import注解的作用为解析指定的class类,如果是简单的java类就直接作为一个bean放入容器中,如果是@Configuration就正常当做配置类解析,

    如果实现了ImportSelector接口,就会调用selectImports接口方法将返回的字符串数组对应的class加载进容器并递归解析;

    如果实现了ImportBeanDefinitionRegistrar接口,就会调用registerBeanDefinitions接口方法,通过这种方式可以自由的注册Bean到IOC容器中,mybatis的MapperScan注解就是通过这种方式扩展的

    org.mybatis.spring.annotation.MapperScannerRegistrar,关于mybatis扩展的详细内容单独写一篇博文

     下面看下spring代码是怎么处理这段逻辑的,入口为下方这个BeanDefinitionRegistryPostProcessor:

    org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

    BeanDefinitionRegistryPostProcessor的调用入口在org.springframework.context.support.AbstractApplicationContext#refresh这里,详细的可以参考spring启动过程那篇博文:

    该后处理bean能处理哪些bean?org.springframework.context.annotation.ConfigurationClassUtils#checkConfigurationClassCandidate给出了答案

     

     

     首先是要有Configuration注解,其次是看org.springframework.context.annotation.ConfigurationClassUtils#isConfigurationCandidate

     

     是的,就是处理有Configuration注解,并且至少有这四个注解中的一个Component、ComponentScan、Import、ImportResource

    回到org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

     解析的核心方法为org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

    ComponentScan注解的处理:

     其他注解的处理:

     重点看到@Import注解的处理逻辑:

    for (SourceClass candidate : importCandidates) {
          // ImportSelector注解处理逻辑 if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); }
    // 实现DeferredImportSelector接口的selector暂存放到最后处理,因为实现该接口的类通常会带有 @Conditional注解,只有等到其他所有
    // bean都加载完了才能确定是否要添加该bean,典型的就是springboot的自动装配selector:org.springframework.boot.autoconfigure.AutoConfigurationImportSelector
    // 典型的注解如ConditionalOnMissingBean
    if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else {
    // 普通的ImportSelector就直接调用selectImports返回字符串数组,并递归解析这些class String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } }
    // 实现ImportBeanDefinitionRegistrar接口的selector会先实例化并把实例放入到configClass的importBeanDefinitionRegistrars中暂存
    // parse完回到后处理bean中,下方的ConfigurationClassBeanDefinitionReader会丛中注册beanDefinition
    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 = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else {
    // 这里的英文注释很清楚了吧,都不是上面两种情况的话直接当做@Configuration处理 // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } }

    org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass最后会把当前configClass放入集合

     parse完回到后处理bean:ConfigurationClassPostProcessor

     下面看下reader方法:

    核心方法org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass

     至此,@Import方式扩展注册beanDefinition就基本都清晰了。

  • 相关阅读:
    c#项目架构搭建经验
    c++ template怎么使用及注意事项
    c++怎么将一个类,拆分出接口类,和实现类
    c++l类
    错过C++
    Fixed 鸟粪一样的TreeView下的NodeMouseDoubleClick Bug
    Oracle 12C 新特性之表分区带 异步全局索引异步维护(一次add、truncate、drop、spilt、merge多个分区)
    Oracle 12C 新特性之在线重命名、迁移活跃的数据文件
    Oracle 12C 新特性之级联truncate
    Oracle 12C 新特性之扩展数据类型(extended data type)
  • 原文地址:https://www.cnblogs.com/reboot30/p/14875887.html
Copyright © 2020-2023  润新知