spring源码分析(1)——AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的初始化

        为了更容易的理解spring源码,我们使用一个简单的hello world的例子来分析。

        Spring的版本是5.0.4,需要jdk8以上支持

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.4.RELEASE</version>
    </dependency>
</dependencies>

        例子来自于Spring官网示例,请自行下载。

        首先从main函数开始

publicstatic void main(String[] args) {
    ApplicationContext context = 
        newAnnotationConfigApplicationContext(Application.class);
    MessagePrinter printer =context.getBean(MessagePrinter.class);
    printer.printMessage();
}

        AnnotationConfigApplicationContext 是spring 3.0以后引入的类,用于处理spring注解。

        AnnotationConfigApplicationContext继承了GenericApplicationContext,而GenericApplicationContext实现了BeanDefinitionRegistry。

        Spring容器里通过BeanDefinition对象来表示Bean,BeanDefinition描述了Bean的配置信息。而BeanDefinitionRegistry接口提供了向容器注册,删除,获取BeanDefinition对象的方法。简单来说,BeanDefinitionRegistry可以用来管理BeanDefinition,所以理解AnnotationConfigApplicationContext很关键,它是spring加载bean,管理bean的最重要的类。

        我们跟进这个构造方法继续。

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
   this();
   register(annotatedClasses); 
   refresh();
}

        this()调用本身无参的构造函数。

public AnnotationConfigApplicationContext() {
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

        AnnotatedBeanDefinitionReader是一个读取注解的Bean读取器,这里将this传了进去。

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
   this(registry, getOrCreateEnvironment(registry));
}

        这里将AnnotationConfigApplicationContext注册为管理BeanDefinition的BeanDefinitionRegistry,也就是说,spring中bean的管理完全交给了AnnotationConfigApplicationContext。

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
   this.registry = registry;
   this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
   AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)会把一些自动注解处理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中,具体的代码就不粘了,这里加入了如下6个处理器:

        1:bean名称为org.springframework.context.annotation.internalConfigurationAnnotationProcessor的ConfigurationClassPostProcessor。

        ConfigurationClassPostProcessor是一个BeanFactory和BeanDefinitionRegistry处理器,BeanDefinitionRegistry处理方法能处理@Configuration等注解。ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()方法内部处理@Configuration,@Import,@ImportResource和类内部的@Bean。

        ConfigurationClassPostProcessor类继承了BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor类继承了BeanFactoryPostProcessor。通过BeanDefinitionRegistryPostProcessor可以创建一个特别后置处理器来将BeanDefinition添加到BeanDefinitionRegistry中。它和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。在Mybatis与Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor来对Mapper的BeanDefinition进行了后置的自定义处理。

        2:bean名称为org.springframework.context.annotation.internalAutowiredAnnotationProcessor的AutowiredAnnotationBeanPostProcessor。AutowiredAnnotationBeanPostProcessor是一个BeanPostProcessor,注意BeanPostProcessor和BeanFactoryPostProcessor的区别。AutowiredAnnotationBeanPostProcessor是用来处理@Autowired注解和@Value注解的。

        3:bean名称为org.springframework.context.annotation.internalRequiredAnnotationProcessor的RequiredAnnotationBeanPostProcessor。这是用来处理@Required注解。

        4:bean名称为org.springframework.context.annotation.internalCommonAnnotationProcessor的CommonAnnotationBeanPostProcessor。CommonAnnotationBeanPostProcessor提供对JSR-250规范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。

        5:bean名称为org.springframework.context.annotation.internalPersistenceAnnotationProcessor的PersistenceAnnotationBeanPostProcessor。EventListenerMethodProcessor提供@PersistenceContext的支持。

        6:bean名称为org.springframework.context.annotation.internalEventListenerProcessor的EventListenerMethodProcessor。EventListenerMethodProcessor提供@ EventListener  的支持。@ EventListener实在spring4.2之后出现的,可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener。

public AnnotationConfigApplicationContext() {
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

        到此AnnotatedBeanDefinitionReader初始化完毕。总结一下,AnnotatedBeanDefinitionReade读取器用来加载class类型的配置,在它初始化的时候,会预先注册一些BeanPostProcessor和BeanFactoryPostProcessor,这些处理器会在接下来的spring初始化流程中被调用。

        接下来初始化ClassPathBeanDefinitionScanner。

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
      Environment environment, @Nullable ResourceLoader resourceLoader) {
   this.registry = registry;
   if (useDefaultFilters) {
      registerDefaultFilters();
   }
   setEnvironment(environment);
   setResourceLoader(resourceLoader);
}

        分析registerDefaultFilters()方法:

        ClassPathBeanDefinitionScanner继承了 ClassPathScanningCandidateComponentProvider。registerDefaultFilters() 就是 ClassPathScanningCandidateComponentProvider中的方法。

private final List<TypeFilter> includeFilters = new LinkedList<>();

private final List<TypeFilter> excludeFilters = new LinkedList<>();

....

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.debug("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.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-330 API not available - simply skip.
   }
}

        ClassPathScanningCandidateComponentProvider中有两个final类型的List,分别是includeFilters和excludeFilters。这两个对象在ClassPathScanningCandidateComponentProvider这个类执行scanCandidateComponents()方法,也就是扫描给定类路径的包的时候,会充当过滤规则,includeFilters中的就是满足过滤规则的,excludeFilters则是不满足过滤规则的。

        该方法为includeFilters加入了三个TypeFilter,具体来说,是三个AnnotationTypeFilter,它是TypeFilter的一个实现,用于判断类的注解修饰型是否满足要求。从中可知通过 @Component、@javax.annotation.ManagedBean 和 @javax.inject.Named 以及标记了这些 Annotation 的新 Annotation 注解过的 Java 对象即为 Spring 框架通过 Annotation 配置的默认规则。注意@service,@controller等都继承了@component,是符合规则的。

        分析setResourceLoader ()方法:

@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
   this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
   this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
   this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}

        setResourceLoader()方法中为ResourcePatternResolver,MetadataReaderFactory和CandidateComponentsIndex设定初始值。

        1:ResourcePatternResolver是一个接口,继承了ResourceLoader,可以用来获取Resource 实例。ResourcePatternResolver中申明它默认的扫描文件 Pattern 为”**/*.class”,我们使用的AnnotationConfigApplicationContext或者说是任何的ApplicationContext都实现了这个接口,所以这里将AnnotationConfigApplicationContext传给了ResourcePatternResolver。

        2:MetadataReaderFactory用于解析资源信息对应的元数据。

        3:CandidateComponentsIndexLoader.loadIndex () 方法是spring5.0以后加入的新特性,Spring Framework 5 改进了扫描和识别组件的方法,使大型项目的性能得到提升。目前,扫描是在编译时执行的,而且向 META-INF/spring.components 文件中的索引文件添加了组件坐标。该索引是通过一个为项目定义的特定平台应用的构建任务来生成的。标有来自 javax 包的注解的组件会添加到索引中,任何带 @Index 注解的类或接口都会添加到索引中。如果没有META-INF/spring.components这个文件,则返回空,这里返回空。

        至此,ClassPathBeanDefinitionScanner初始化完毕,总结一下,ClassPathBeanDefinitionScanner是一个扫描指定类路径中注解Bean定义的扫描器,在它初始化的时候,会初始化一些需要被扫描的注解,初始化用于加载包下的资源的Loader。

        AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的初始化是spring上线文初始化的起点,很多预加载的类会在spring接下来的初始化中发挥作用。

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/shenmaxiang/article/details/79377236
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞