zoukankan      html  css  js  c++  java
  • 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就基本都清晰了。

  • 相关阅读:
    让pv3d(papervision3D)支持单帧前进、后退(nextFrame)。
    4399 威武三国 网页游戏破解。
    策划进化史一 (2013-12-21)
    Java的一个高性能快速深拷贝方法。Cloneable?
    as3commons-bytecode 获取所有类的一个BUG
    MYSQL 大文件无法导入的问题。
    诡异的 未处理的IOErrorEvent 2035
    一个用微软官方的OpenXml读写Excel 目前网上不太普及的方法。
    如何在高并发环境下设计出无锁的数据库操作(Java版本)
    达洛克战记3 即将开服! What's New!
  • 原文地址:https://www.cnblogs.com/reboot30/p/14875887.html
Copyright © 2011-2022 走看看