美文网首页springspring
@Import注解源码分析

@Import注解源码分析

作者: 念䋛 | 来源:发表于2021-01-26 21:47 被阅读0次

    Bean的生产,首先是为bean定义出一个beanDefinition(bean定义),再根据beanDefinition创建bean, beanDefinition存入beanDifinitionMap之前会创建ConfigurationClass类,spring根据ConfigurationClass的信息,将beanDefinition存储map中,beanDefinition包括很多的信息,例如是否为单例,多例,是否为懒加载,DependsOn(创建bean之前需要创建的bean),是否@Primary,autowireMode,beanClass,initMethodName等等的信息.所有的bean定义都会存放进bean工厂的beanDefinitionMap中,后续会遍历map中的beanDefinition,并创建bean,如果beanDefinitionMap中不存在则不会创建.@Import的作用和@Component的作用有一些相似,都会创建bean.了解这些可以帮助我们分析@Import注解,本文也会结合源码分析@Import注解
    Import只有一个变量 value

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Import {
    
       /**
        * {@link Configuration @Configuration}, {@link ImportSelector},
        * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
        */
       Class<?>[] value();
    
    }
    
    

    @Import首先是在
    ConfigurationClassParser#doProcessConfigurationClass的processImports(configClass, sourceClass, getImports(sourceClass), filter, true);被解析,此方法只是把类的信息封装进ConfigruationClass中

    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
          Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
    
       if (importCandidates.isEmpty()) {
          return;
       }
    
       if (checkForCircularImports && isChainedImportOnStack(configClass)) {
          this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
       }
       else {
          this.importStack.push(configClass);
          try {
             //获取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();
                   //实例化实现SelectImport接口的类
                   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));
                   }
                   else {
                      //调用ImportSelector的selectImports方法,返回String数组,类的全类名称
                      String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                      //String[]返回的类可能实现了ImportSelector或者ImportBeanDefinitionRegistrar接口,也有可能是
                      //一个普通的类,这里递归解析,直到为一个普通的类,或者说扫面到不实现ImportSelector接口的类
                      Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                      processImports(configClass, currentSourceClass, importSourceClasses, false);
                   }
                }
                //判断类是否实现了ImportBeanDefinitionRegistrar接口,不调用接口的实现方法,而是存入进configClass中
                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);
                   //保存我们的类到configClass中,后续会被调用
                   configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                else {
    //如果没有实现上面两个接口, candidate.asConfigClass(configClass)标注importedBy,后续判断是否是通过@Import导入的
    //继续执行processConfigurationClass方法,可以点进去看一下,这里不扩展了, processConfigurationClass的作用就是
    //类是否标注了@Component@ PropertySources@ ComponentScans@ ImportResource@Import这些注解,并根据相应的注解解析类
                   this.importStack.registerImport(
                         currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                   processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
                }
             }
          }
          catch (BeanDefinitionStoreException ex) {
             throw ex;
          }
          catch (Throwable ex) {
             throw new BeanDefinitionStoreException(
                   "Failed to process import candidates for configuration class [" +
                   configClass.getMetadata().getClassName() + "]", ex);
          }
          finally {
             this.importStack.pop();
          }
       }
    }
    
    

    通过上面的源码分析,分析@Import导入的类是否实现了ImportSelector和BeanDefinitionRegistrar接口,如果同时实现只解析ImportSelector

    上面只是将一些信息存放到configclass中,代码执行到ConfigurationClassPostProcessor # processConfigBeanDefinitions 方法的this.reader.loadBeanDefinitions(configClasses);这段代码是开始解析configClasses,通过for循环遍历所有的configClasses;目的是向beanDefinitionMap注册beanDefinition

    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;
       }
    //这里就是解析@Import类,上面提到过importedBy,这里就会解析
       if (configClass.isImported()) {
          registerBeanDefinitionForImportedConfigurationClass(configClass);
       }
       for (BeanMethod beanMethod : configClass.getBeanMethods()) {
          loadBeanDefinitionsForBeanMethod(beanMethod);
       }
    
       loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    //这里解析继承ImportBeanDefinitionRegistrars类,调用registerBeanDefinitions方法,其中两个入参AnnotationMetadata importingClassMetadata和 BeanDefinitionRegistry registry ,importingClassMetadata为原类信息,注意不是ImportBeanDefinitionRegistrars的实现类,是标注@Import类的元信息 registry可以手动的向beanDefinitionMap中注册beanDefinition
    
       loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }
    

    registerBeanDefinitionForImportedConfigurationClass方法

    private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
       //获取配置类的元信息
       AnnotationMetadata metadata = configClass.getMetadata();
       //构建beanDefinition
       AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
       //设置scope
       ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
       configBeanDef.setScope(scopeMetadata.getScopeName());
       //获取bean的名称
       String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
       //处理我们的JRS250组件的
       AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
    
       BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
       definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
       //注册我们的bean定义到我们的容器中
       this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
       configClass.setBeanName(configBeanName);
    
       if (logger.isDebugEnabled()) {
          logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
       }
    }
    
    

    经过上面的分析,大致的了解@Import的机制,下面对分析@Import的使用

    @Import(A.class)

    1. A没有实现ImportBeanDefinitionRegistrar和ImportSelector两个接口

    A将会存放进IOC容器中

    1. A实现ImportSelector

    A类不会存放进IOC容器中,调用selectImprots方法,Run存放进IOC容器中

    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{Run.class.getName ()};
    }
    
    
    1. A类实现ImportBeanDefinitionRegistrar接口
      A类依旧不会存入IOC容器中,在调用registerBeanDefinitions方法的时候将Walk存放进IOC容器中,并设置beanName为walk
      当然这里可以操作beanDefinition我们就可以做很多的事,设置bean单例还是多例,是否为懒加载,dependsOn等很多的信息.
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        GenericBeanDefinition beanDefinition=new GenericBeanDefinition ();
        beanDefinition.setBeanClass(Walk.class);
        registry.registerBeanDefinition("walk",beanDefinition);
    }
    
    
    1. @Import 配置 ImportAware使用

    可以看我分享的文章 https://www.jianshu.com/p/8378b9f491ae

    相关文章

      网友评论

        本文标题:@Import注解源码分析

        本文链接:https://www.haomeiwen.com/subject/ebmnzktx.html