Spring Bean定义的加载解析过程之注解的过程

Posted 狐言不胡言

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Bean定义的加载解析过程之注解的过程相关的知识,希望对你有一定的参考价值。

@TOC

注解的使用

public static void main(String[] args) {
   ApplicationContext context = new AnnotationConfigApplicationContext(
         "edu.demo.spring.bean","edu.demo.spring.ext");
   Boy boy = context.getBean(Lad.class);
   boy.sayLove();
}

上面是示例代码,主要的步骤如下图:

要进行debug分析的话,需要在DefaultListableBeanFactory类下,registerBeanDefinition方法中打断点进行调试分析。

注解的加载处理

下图是具体的调用栈信息:

第一步:AnnotationConfigApplicationContext

/**
* 创建一个AnnotationConfigApplicationContext容器,然后在给定的包下扫描组件
* 把这些组件注册成bean定义信息,并且自动刷新容器
* @param basePackages 扫描组件类的包,可以定义多个
*/
public AnnotationConfigApplicationContext(String... basePackages) {
   this();
   scan(basePackages);
   refresh();
}
/**
 * 在这个构造函数中,构建了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner对象
 * AnnotatedBeanDefinitionReader用来解读注解信息
 * ClassPathBeanDefinitionScanner用来扫描包
 */
public AnnotationConfigApplicationContext() {
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

AnnotationConfigApplicationContext类中,主要做的工作,就是在构造函数中构建了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner对象。

第二步:AnnotatedBeanDefinitionReader

/**
 * 从给定的Bean定义注册接口中创建一个AnnotatedBeanDefinitionReader
 * 然后进行初始化AnnotatedBeanDefinitionReader
 */
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this(registry, getOrCreateEnvironment(registry));
}

/**
 * 从BeanDefinitionRegistry获取Environment
 * 如果获取不到就返回一个StandardEnvironment
 */
private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    if (registry instanceof EnvironmentCapable) {
        return ((EnvironmentCapable) registry).getEnvironment();
    }
    return new StandardEnvironment();
}

 public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
     //非空判断
     Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
     Assert.notNull(environment, "Environment must not be null");
     this.registry = registry;
     this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
     AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

在AnnotatedBeanDefinitionReader类中,主要做的事情,就是初始化AnnotatedBeanDefinitionReader对象。

第三步:AnnotationConfigUtils

/**
  * 注册所有关于注解配置的处理器,注册到BeanFactory
    * @param registry the registry to operate on
    */
   public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
      registerAnnotationConfigProcessors(registry, null);
   }

 /**
  * 注册所有关于注解配置的处理器,注册到BeanFactory
  */
 public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
         BeanDefinitionRegistry registry, @Nullable Object source) {

     ......

     //将需要使用到的各种处理器注册成bean定义,然后注入到bean工厂中,作为bean来使用
     Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

     //@Configuration注解类后置处理器
     if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
     }

     //@Autowired注解类后置处理器
     if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
     }

     // 检查是否支持JSR-250
     if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
     }

     // 检查是否支持JPA
     if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition();
         try {
             def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                     AnnotationConfigUtils.class.getClassLoader()));
         }
         catch (ClassNotFoundException ex) {
             throw new IllegalStateException(
                     "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
         }
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
     }

     if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
     }

     if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
     }

     return beanDefs;
 }

private static BeanDefinitionHolder registerPostProcessor(
      BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

   definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
   registry.registerBeanDefinition(beanName, definition);
   return new BeanDefinitionHolder(definition, beanName);
}

通过方法的名字可以知道,这一步主要做的事情,就是注册注解配置的Processor,注册到内部的BeanFactory中,这里的Processor是做什么用的?

在注解的加载过程中,除了加载注册自己的Bean以外,Spring内部也有各种bean注入到工厂中,用来处理各种逻辑,比如上面代码中的,注解bean定义的相关处理对象,都是通过bean定义注入到工厂中的。

第四步:

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}

向BeanFactory中注册注册处理器的Bean定义信息。

从上面的调用栈来看,这里并没有注册我们自己定义的Bean定义信息,而是一些Processor。而且也没有看到它做扫描包的工作。

从第一步的代码看到,这里还只是在AnnotationConfigApplicationContext的构造函数中,第二步才执行scan方法,第三步才是refresh方法。注解的方式是在构造函数中就进行了各种初始化的准备,而XML的方式是在refresh方法中就进行了Bean定义的注册。

registerAnnotationConfigProcessors,从方法名上来理解,就是注册了一些注解配置的处理器,下面从ConfigurationClassPostProcessor入手来看下,这些Processor具体是用来干什么的。

/**
 * {@link BeanFactoryPostProcessor} used for bootstrapping processing of
 * {@link Configuration @Configuration} classes.
 *
 * <p>Registered by default when using {@code <context:annotation-config/>} or
 * {@code <context:component-scan/>}. Otherwise, may be declared manually as
 * with any other BeanFactoryPostProcessor.
 *
 * <p>This post processor is priority-ordered as it is important that any
 * {@link Bean} methods declared in {@code @Configuration} classes have
 * their corresponding bean definitions registered before any other
 * {@link BeanFactoryPostProcessor} executes.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @author Phillip Webb
 * @since 3.0
 */
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
      PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
}

通过注释可以看到,这是在启动阶段用来处理@Configuration注解的BeanFactoryPostProcessor,但是这里并没有看到BeanFactoryPostProcessor,但是有一个接口BeanDefinitionRegistryPostProcessor,点进去可以看到,它的父级就是BeanFactoryPostProcessor。

ConfigurationClassPostProcessor的继承体系如下:

下面来看下BeanDefinitionRegistryPostProcessor:

/**
 * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
 * the registration of further bean definitions <i>before</i> regular
 * BeanFactoryPostProcessor detection kicks in. In particular,
 * BeanDefinitionRegistryPostProcessor may register further bean definitions
 * which in turn define BeanFactoryPostProcessor instances.
 *
 * @author Juergen Hoeller
 * @since 3.0.1
 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
 */
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

   /**
    * Modify the application context\'s internal bean definition registry after its
    * standard initialization. All regular bean definitions will have been loaded,
    * but no beans will have been instantiated yet. This allows for adding further
    * bean definitions before the next post-processing phase kicks in.
    * @param registry the bean definition registry used by the application context
    * @throws org.springframework.beans.BeansException in case of errors
    */
   void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

BeanDefinitionRegistryPostProcessor扩展了BeanFactoryPostProcessor,增加了
BeanDefinitionRegistry位置的处理,即它可以提前对注册好的BeanDefinitionRegistry进行前置处理

从上图可以看到,在bean的构建过程中,箭头所指向的地方,都可以进行扩展,所以不难看出BeanDefinitionRegistryPostProcessor的作用

再来看下BeanFactoryPostProcessor:

@FunctionalInterface
public interface BeanFactoryPostProcessor {

   /**
    * Modify the application context\'s internal bean factory after its standard
    * initialization. All bean definitions will have been loaded, but no beans
    * will have been instantiated yet. This allows for overriding or adding
    * properties even to eager-initializing beans.
    * @param beanFactory the bean factory used by the application context
    * @throws org.springframework.beans.BeansException in case of errors
    */
   void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

从上面的注释信息,可以知道,这里所做的事情就是,在所有的bean定义加载完成,但是还没有进行实例化之前,对BeanFactory中的bean定义信息可以进行一些想要做的处理。

这是Spring提供的扩展点之一,在BeanFactory开始创建bean实例之前,对beanFactory中的bean定义信息进行一些处理

装载外部的配置文件:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
   <property name="locations" value="classpath:application.properties"/>
</bean>

下面是简单实现的例子:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      System.out.println(this + "BeanFactoryPostProcessor工作了..................................");
   }
}

在测试类里面,增加上面类所在包的扫描:

ApplicationContext context = new AnnotationConfigApplicationContext(
      "edu.demo.spring");

下面是它的调用栈:

在PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors创建并执行的这个MyBeanFactoryPostProcessor。

输出如下:

IOC容器与BeanFactoryPostProcessor的关系

注解的扫描过程


在上图的位置设置断点,然后释放,最后到DefaultListableBeanFactory.registerBeanDefinition断点可以得到调用栈。

第一步:

/**
 * 在指定的包内执行扫描操作
 * <p>Note that {@link #refresh()} must be called in order for the context
 * to fully process the new classes.
 * @param basePackages the packages to scan for component classes
 * @see #register(Class...)
 * @see #refresh()
 */
@Override
public void scan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   this.scanner.scan(basePackages);
}
/**
 * 在指定的包内执行扫描操作
 * 构建并初始化ClassPathBeanDefinitionScanner扫描器对象,开始进行扫描
 * @param basePackages the packages to check for annotated classes
 * @return number of beans registered
 */
public int scan(String... basePackages) {
   //获取扫描到的bean定义的个数
   int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

   doScan(basePackages);

   // Register annotation config processors, if necessary.
   if (this.includeAnnotationConfig) {
      AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
   }

   return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

第二步:

/**
 * Perform a scan within the specified base packages,
 * returning the registered bean definitions.
 * <p>This method does <i>not</i> register an annotation config processor
 * but rather leaves this up to the caller.
 * @param basePackages the packages to check for annotated classes
 * @return set of beans registered if any for tooling registration purposes (never {@code null})
 */
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
}

完成包名下的bean定义的扫描,并且返回注册的bean定义集合。

第三步:

// 完成bean定义到bean工厂的注册
registerBeanDefinition(String, BeanDefinition):929, DefaultListableBeanFactory

(org.springframework.beans.factory.support)

registerBeanDefinition(String, BeanDefinition):323, GenericApplicationContext

(org.springframework.context.support)

registerBeanDefinition(BeanDefinitionHolder, BeanDefinitionRegistry):164,

BeanDefinitionReaderUtils (org.springframework.beans.factory.support)

registerBeanDefinition(BeanDefinitionHolder, BeanDefinitionRegistry):320,

ClassPathBeanDefinitionScanner (org.springframework.context.annotation)

重点的部分在doScan方法,下面来看下它做了什么:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
   //遍历要扫描的包
   for (String basePackage : basePackages) {
      //找到指定包下的所有候选组件(配置的bean)
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      //扫描所有的候选组件
      for (BeanDefinition candidate : candidates) {
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) {
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         if (candidate instanceof AnnotatedBeanDefinition) {
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            //注册bean定义到BeanFactory中
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}

进入findCandidateComponents方法:

/**
 * 扫描指定的路径,获取候选组件
 * @param basePackage the package to check for annotated classes
 * @return a corresponding Set of autodetected bean definitions
 */
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   //如果有组件索引并且索引支持包含的filters,就从组件索引中获取获选组件
   if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   else {
      // 否则,进行类目录下指定包的扫描
      return scanCandidateComponents(basePackage);
   }
}

组件索引请查看官方文档:https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/core.html#beans-scanning-index

如果要使用组件索引,需要加入下面的maven配置:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.1.8.RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>

这里没有使用到,所以进入了scanCandidateComponents方法:

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
   //所有候选组件的集合
   Set<BeanDefinition> candidates = new LinkedHashSet<>();
   try {
      //构建扫描包的路径表达式,类似于切点表达式
      //classpath*:edu/demo/spring/ext/**/*.class
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + \'/\' + this.resourcePattern;
      // ResourcePatternResolver扫描包获取到.class文件
      // 扫描的逻辑:在包下找.class文件,这里要求能够灵活指定包,就需要用到模式匹配
      // 默认用到的Ant Path模式匹配,如指定的包 edu.demo.**.service
      Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
      boolean traceEnabled = logger.isTraceEnabled();
      boolean debugEnabled = logger.isDebugEnabled();
      for (Resource resource : resources) {
         if (traceEnabled) {
            logger.trace("Scanning " + resource);
         }
         if (resource.isReadable()) {
            try {
               // MetadataReader,元数据读取器,类似xml读取器
               MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
               if (isCandidateComponent(metadataReader)) {
                  // 最终通过MetadataReader用ScannedGenericBeanDefinition装载了注解bean定义
                  ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                  sbd.setSource(resource);
                  //必须是一个可以继承的类,不能是接口和封闭类,抽象类必须有Lookup注解
                  if (isCandidateComponent(sbd)) {
                     if (debugEnabled) {
                        logger.debug("Identified candidate component class: " + resource);
                     }
                     candidates.add(sbd);
                  }
                  else { // 忽略,不是一个顶层的具体类
                     if (debugEnabled) {
                        logger.debug("Ignored because not a concrete top-level class: " + resource);
                     }
                  }
               }
               else { // 忽略,不能匹配到过滤器
                  if (traceEnabled) {
                     logger.trace("Ignored because not matching any filter: " + resource);
                  }
               }
            }
            catch (Throwable ex) {
               throw new BeanDefinitionStoreException(
                     "Failed to read candidate component class: " + resource, ex);
            }
         }
         else {
            if (traceEnabled) {
               logger.trace("Ignored because not readable: " + resource);
            }
         }
      }
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
   }
   return candidates;
}

进入getResourcePatternResolver方法:

private ResourcePatternResolver getResourcePatternResolver() {
   if (this.resourcePatternResolver == null) {
      this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
   }
   return this.resourcePatternResolver;
}

PathMatchingResourcePatternResolver类:能将指定的资源位置路径解析为一个或多个匹配的资源。可以是一对一的资源指定,也可以是一对多的匹配模式,通过ant path格式、classpath*:前缀

public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
    // ......

    // 默认采用AntPathMatcher
    private PathMatcher pathMatcher = new AntPathMatcher();

    // ......
}

模式匹配的关系图:

下面看下ScannedGenericBeanDefinition:

public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {

   private final AnnotationMetadata metadata;

   /**
    * Create a new ScannedGenericBeanDefinition for the class that the
    * given MetadataReader describes.
    * @param metadataReader the MetadataReader for the scanned target class
    */
   public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
      Assert.notNull(metadataReader, "MetadataReader must not be null");
      this.metadata = metadataReader.getAnnotationMetadata();
      setBeanClassName(this.metadata.getClassName());
      setResource(metadataReader.getResource());
   }

   @Override
   public final AnnotationMetadata getMetadata() {
      return this.metadata;
   }

   @Override
   @Nullable
   public MethodMetadata getFactoryMethodMetadata() {
      return null;
   }
}

继承自GenericBeanDefinition类,基于ASM Cla***eader的AnnotatedBeanDefinition实现,支持注解元数据。

在这里为什么要使用AnnotatedBeanDefinition而不使用GenericBeanDefinition?

下面看下AnnotatedBeanDefinition接口提供的两个方法:

public interface AnnotatedBeanDefinition extends BeanDefinition {

   /**
    * 获取注解的元数据
    * Obtain the annotation metadata (as well as basic class metadata)
    * for this bean definition\'s bean class.
    * @return the annotation metadata object (never {@code null})
    */
   AnnotationMetadata getMetadata();

   /**
    * 获取工厂方法的元数据
    * Obtain metadata for this bean definition\'s factory method, if any.
    * @return the factory method metadata, or {@code null} if none
    * @since 4.1.1
    */
   @Nullable
   MethodMetadata getFactoryMethodMetadata();

}

元数据信息

Spring中定义了一套方案来描述一个类、一个类上的注解、一个方法等的描述接口,里面定义了一些相关的操作。
比如:

  • 类:类的名称是什么,用了什么修饰符
  • 注解:类上的注解的名字,注解的元注解信息有什么,注解的注释信息是什么,注解里面有哪些属性等

MetadataReader接口:

/**
 * Simple facade for accessing class metadata,
 * as read by an ASM {@link org.springframework.asm.Cla***eader}.
 * 通过ASM的Cla***eader读取类的元信息,提供一个简单的外观模式。
 * 1. 用ASM来实现这个功能;2. 这是一个简单的外观模式实现
 *
 * @author Juergen Hoeller
 * @since 2.5
 */
public interface MetadataReader {

   /**
    * Return the resource reference for the class file.
    * 返回类的资源文件
    */
   Resource getResource();

   /**
    * Read basic class metadata for the underlying class.
    */
   ClassMetadata getClassMetadata();

   /**
    * Read full annotation metadata for the underlying class,
    * including metadata for annotated methods.
    * 返回注解的元数据信息 
    */
   AnnotationMetadata getAnnotationMetadata();

}

实现类:SimpleMetadataReader

final class SimpleMetadataReader implements MetadataReader {
       SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader)
    throws IOException {
    // 构建注解元数据读取访问者
    SimpleAnnotationMetadataReadingVisitor visitor = new
    SimpleAnnotationMetadataReadingVisitor(classLoader);
    // 创建资源对应的ASM Cla***eader对象,并且对用visitor对Cla***eader对象进行访问解读
    getCla***eader(resource).accept(visitor, PARSING_OPTIONS);
    // 扫描到的带有注解的类
    this.resource = resource;
    // 获得注解元数据信息
    this.annotationMetadata = visitor.getMetadata();
    }
}

ASM是一个低层次的字节码操作库,官网地址:https://asm.ow2.io/

Spring中通过ASM字节码操作库来读取的类信息、注解信息,它们的类关系图如下:

扫描过滤器

/**
 * Determine whether the given class does not match any exclude filter
 * and does match at least one include filter.
 * @param metadataReader the ASM Cla***eader for the class
 * @return whether the class qualifies as a candidate component
 */
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   for (TypeFilter tf : this.excludeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return false;
      }
   }
   for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return isConditionMatch(metadataReader);
      }
   }
   return false;
}
<context:component-scan base-package="edu.demo.spring.web" >
   <context:exclude-filter type="annotation" expression="@Service"/>
   <context:include-filter type="annotation" expression="@Controller"/>
</context:component-scan>

filter可以使用上面的方式在xml文件中进行配置,exclude是不包含这些组件,include是需要包含这些组件。

@service @controller等是怎么匹配到的呢,默认情况下的filter是什么样的,看下面的代码:

protected void registerDefaultFilters() {
   this.includeFilters.add(new AnnotationTypeFilter(Component.class));
   ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
      logger.trace("JSR-250 \'javax.annotation.ManagedBean\' found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
   }
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
      logger.trace("JSR-330 \'javax.inject.Named\' annotation found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-330 API not available - simply skip.
   }
}

AnnotationTypeFilter的父类AbstractTypeHierarchyTraversingFilter#match
(MetadataReader,MetadataReaderFactory)方法,最后会到AnnotationTypeFilter#matchSelf方法:

@Override
protected boolean matchSelf(MetadataReader metadataReader) {
   AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
   // 包含指定的注解 或者 注解里面包含指定注解, 比如指定的@Componet注解,在@Service注解中有包含
   return metadata.hasAnnotation(this.annotationType.getName()) ||
         (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}

自定义实现TypeFilter:

public class MyTypeFilter implements TypeFilter {
   @Override
   public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
         throws IOException {
      // 使用metadataReader中的类信息、注解信息来进行你的过滤判断逻辑
      return metadataReader.getClassMetadata().getClassName().equals(Lad.class.getName());
   }
}

Bean定义的注册

/**
 * 将给定的bean定义信息注册到bean工厂中
 * Register the given bean definition with the given bean factory.
 * @param definitionHolder the bean definition including name and aliases
 * @param registry the bean factory to register with
 * @throws BeanDefinitionStoreException if registration failed
 */
public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   //获取beanName
   String beanName = definitionHolder.getBeanName();
   //通过bean工厂注册bean定义信息
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   //把beanName和别名进行绑定,如果存在别名就注册别名进去
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

核心的部分在DefaultListableBeanFactory#registerBeanDefinition方法中:

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   //判断beanName和beanDefinition信息是否为空
   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");

   //如果存在继承自AbstractBeanDefinition的bean定义
   //那么就对这个bean进行校验
   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   //是否已经存在相关的bean定义了
   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   //bean定义已经存在的情况下
   if (existingDefinition != null) {
      //如果不允许重写覆盖,则抛出异常
      if (!isAllowBeanDefinitionOverriding()) {
         throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      //运行重写覆盖的处理,进行一些日志信息的打印,告知处理的信息
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         if (logger.isInfoEnabled()) {
            logger.info("Overriding user-defined bean definition for bean \'" + beanName +
                  "\' with a framework-generated bean definition: replacing [" +
                  existingDefinition + "] with [" + beanDefinition + "]");
         }
      }
      else if (!beanDefinition.equals(existingDefinition)) {
         if (logger.isDebugEnabled()) {
            logger.debug("Overriding bean definition for bean \'" + beanName +
                  "\' with a different definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      else {
         if (logger.isTraceEnabled()) {
            logger.trace("Overriding bean definition for bean \'" + beanName +
                  "\' with an equivalent definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      //覆盖原有的bean定义信息
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   //beanName的bean定义不存在的情况
   else {
      //当前的bean对象是否正在创建
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         //启动期间,同步处理,防止其他地方集合的迭代异常
         synchronized (this.beanDefinitionMap) {
            //使用ConcurrentHashMap进行存储
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            removeManualSingletonName(beanName);
         }
      }
      else {
         // Still in startup registration phase
         //当前bean还没有开始创建,直接put
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   //如果对应的单例bean存在,则重置这个Bean
   if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
   // 需要冻结配置,清除类型映射缓存
   else if (isConfigurationFrozen()) {
      clearByTypeCache();
   }
}

别名的处理,将别名作为Key,beanName作为Value进行map存储

@Override
public void registerAlias(String name, String alias) {
   Assert.hasText(name, "\'name\' must not be empty");
   Assert.hasText(alias, "\'alias\' must not be empty");
   synchronized (this.aliasMap) {
      if (alias.equals(name)) {
         this.aliasMap.remove(alias);
         if (logger.isDebugEnabled()) {
            logger.debug("Alias definition \'" + alias + "\' ignored since it points to same name");
         }
      }
      else {
         String registeredName = this.aliasMap.get(alias);
         if (registeredName != null) {
            if (registeredName.equals(name)) {
               // An existing alias - no need to re-register
               return;
            }
            if (!allowAliasOverriding()) {
               throw new IllegalStateException("Cannot define alias \'" + alias + "\' for name \'" +
                     name + "\': It is already registered for name \'" + registeredName + "\'.");
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Overriding alias \'" + alias + "\' definition for registered name \'" +
                     registeredName + "\' with new target name \'" + name + "\'");
            }
         }
         checkForAliasCircle(name, alias);
         this.aliasMap.put(alias, name);
         if (logger.isTraceEnabled()) {
            logger.trace("Alias definition \'" + alias + "\' registered for name \'" + name + "\'");
         }
      }
   }
}

以上是关于Spring Bean定义的加载解析过程之注解的过程的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码--03--加载bean的定义信息---Spring注解解析原理

2) SpringBootApplication注解详解

Spring注解开发-全面解析常用注解使用方法之生命周期

Spring源码解析 – @Configuration配置类及注解Bean的解析

Spring中Bean定义加载过程解析

Spring之IOC-注解方式