springspring

@Import注解源码分析

2021-01-26  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读