AnnotationConfigApplicationContext 源码分析(一)

AnnotationConfigApplicationContext 源码分析(一):新建对象

本文是作者的个人学习笔记,仅做参考,Spring代码版本5.2.2

AnnotationConfigApplicationContext 作为继承GenericApplicationContext的子类,归属于Spring容器。同时该类实现了AnnotationConfigRegistry注解,在GenericApplicationContext的基础上为容器添加了一下两个功能:

  1. 对携带spring注解的类的注册。

  2. 扫描某个包下携带spring注解的类。

一、AnnotationConfigApplicationContext的基本使用

public class DemoApplication {
  public static void main(String[] args) {
    //1.新建AnnotationConfigApplicationContext对象
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    //2.注册配置类
        applicationContext.register(MyConfiguration.class);
    //3.启动容器
        applicationContext.refresh();
    //4.停止容器
    applicationContext.stop();
    //5.重启容器
        applicationContext.start();
    //6.关闭容器
        applicationContext.close();
  }
}

在AnnotationConfigApplicationContext最基础的使用中,我们启动一个容器需要三个步骤,对应上面的代码

  1. 新建AnnotationConfigApplicationContext对象
  2. 注册配置类
  3. 启动容器

剩下的三个步骤一般不会使用,有时间也将会阅读做分析

  1. 停止容器
  2. 重启容器
  3. 关闭容器

二、新建AnnotationConfigApplicationContext对象

/**
 *  
 **/
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    private final AnnotatedBeanDefinitionReader reader;

    private final ClassPathBeanDefinitionScanner scanner;
  /**
     * Create a new AnnotationConfigApplicationContext that needs to be populated
     * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
     * 创建一个新的AnnotationConfigApplicationContext,它需要通过{@link#register}调用填充,
     * 然后手动{@linkplain#刷新}。
     *
     * 这里初始化了
     */
    public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);

        // Spring的扫描机制
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
  
  public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
    // 内置一个DefaultListableBeanFactory对象
        super(beanFactory);
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
}

由上面我们可以看到新建一个AnnotationConfigApplicationContext对象的时候,将实例化两个类,同时选择性的内置一个DefaultListableBeanFactory对象,以下将做具体的解析

1、 DefaultListableBeanFactory

这个类同GenericApplicationContext一样,都实现了BeanFactory接口,作为容器使用,但是两者没有继承关系。

GenericApplicationContext一般作为资源管理器使用,内部对于bean的管理往往是通过内置一个DefaultListableBeanFactory对象作为Bean管理器。

2、AnnotatedBeanDefinitionReader

/**
 * Convenient adapter for programmatic registration of bean classes.
 * <p>This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
 * the same resolution of annotations but for explicitly registered classes only.
 
 * 便于bean类的编程注册的适配器。
 * <p>这是{@link ClassPathBeanDefinitionScanner}的另一种选择,它应用相同的注释解析,但仅适用于显式注册的类。
 */
public class AnnotatedBeanDefinitionReader {}

AnnotatedBeanDefinitionReader作为一个工具类,用于更方便的注册bean,接下来我们看一下这个类的构造函数

public class AnnotatedBeanDefinitionReader {
    private final BeanDefinitionRegistry registry;
    private ConditionEvaluator conditionEvaluator;

    /**
     * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
     * using the given {@link Environment}.
     * @param registry the {@code BeanFactory} to load bean definitions into,
     * in the form of a {@code BeanDefinitionRegistry}
     * @param environment the {@code Environment} to use when evaluating bean definition
     * profiles.
     *
     * 使用给定的{@link Environment},为给定的注册表创建一个新的{@code AnnotatedBeanDefinitionReader}。
     * @param registry 以{@code BeanDefinitionRegistry}的形式将bean定义加载到{@code BeanFactory}
     * @param environment 在计算bean定义概要文件时要使用的{@code Environment}。
     * @since 3.1
     */
    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
  }
}

由上面代码可以看到,AnnotatedBeanDefinitionReader实例化需要的两个参数

  1. BeanDefinitionRegistry:bean定义的注册器,由GenericApplicationContext实现,AnnotationConfigApplicationContext继承。
  2. Environment:环境变量,这里先不讨论,后面补充

AnnotatedBeanDefinitionReader实例化的逻辑

  1. 持有一个BeanDefinitionRegistry/bean定义的注册器
  2. 通过registry,environment参数创建一个ConditionEvaluator对象,ConditionEvaluator对象的作用是用于解析注解@Conditional,这里先不做过多关注
  3. 通过工具类AnnotationConfigUtils,注册AnnotationConfigProcessors

接下来我们一次看一下ConditionEvaluator对象的创建和解析AnnotationConfigProcessors的注册

ConditionEvaluator对象的创建

/**
 * Internal class used to evaluate {@link Conditional} annotations.
 * 用于计算{@link Conditional}批注的内部类。
 *
 */
class ConditionEvaluator {
    private final ConditionContextImpl context;
  
    /**
     * Create a new {@link ConditionEvaluator} instance.
     * 用于计算{@link Conditional}批注的内部类。
     */
    public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
            @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
        this.context = new ConditionContextImpl(registry, environment, resourceLoader);
    }
}

注册AnnotationConfigProcessors


public abstract class AnnotationConfigUtils {
  /**
     * Register all relevant annotation post processors in the given registry.
     * @param registry the registry to operate on
     * @param source the configuration source element (already extracted)
     * that this registration was triggered from. May be {@code null}.
     * @return a Set of BeanDefinitionHolders, containing all bean definitions
     * that have actually been registered by this call
     * 
     * 注册在给定的注册表中所有相关的批注后置处理器。
     * @param source 触发此注册的配置源元素(已提取)。可能是{@code null}。
     * @return 一组BeanDefinitionHolders,包含此调用实际注册的所有bean定义
     */
  public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {
        //步骤一
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }
        //步骤二
        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

        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));
        }

        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));
        }
        。。。

        return beanDefs;
    }
}

上面代码将分成几部分步骤:

  1. 获取DefaultListableBeanFactory对象,
    1. 需要注意的是,;
    2. 如果beanFactory(DefaultListableBeanFactory不为空),将为该对象设置两个对象,这里不做讨论:
      1. AnnotationAwareOrderComparator
      2. ContextAnnotationAutowireCandidateResolver
  2. 为当前容器registry注册多个BeanFactory后置处理器
    1. 注册的过程
      1. 利用后置处理器类对象和source对象(配置)生成一个BeanDefinition(Bean定义)对象;
      2. 用指定的bean名称和BeanDefinition对象,一起注册到registry中,并返回一个BeanDefinitionHolder对象(该对象持有BeanDefinition对象,bean的名称,bean的别名列表)
      3. 将BeanDefinitionHolder添加到指定列表中,作为最后的结果返回,这里并无利用到结果。
    2. BeanFactory后置处理器将干预Spring在注册,扫描,解析,生成BeanDefinition等的整个过程,后面将会具体解析。
    3. Spring支持用户注册自定义的BeanFactory后置处理器,同时,Spring在不同的容器中也注册实现不同功能的后置处理器,以下是在当前方法中注册的跟注解相关的后置处理器的简单介绍,在后面调用中将做具体解析
      1. CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME:
        1. 作用:内部托管配置注释处理器。
        2. 对应的类:ConfigurationClassPostProcessor.class
      2. AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME
        1. 作用:内部管理的自动注入注解处理器
        2. 对应的类:AutowiredAnnotationBeanPostProcessor.class
      3. COMMON_ANNOTATION_PROCESSOR_BEAN_NAME
        1. 作用:内部管理的JSR-250注释处理器
        2. 对应的类:CommonAnnotationBeanPostProcessor.class
      4. PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME
        1. 作用:内部管理的JPA注释处理器(不一定注入)。
        2. 对应的类:PersistenceAnnotationBeanPostProcessor.class
      5. EVENT_LISTENER_PROCESSOR_BEAN_NAME
        1. 作用:内部管理的@EventListener注释处理器
        2. 对应的类:EventListenerMethodProcessor.class
      6. EVENT_LISTENER_FACTORY_BEAN_NAME
        1. 作用:内部管理的EventListenerFactory。
        2. 对应的类:DefaultEventListenerFactory.class

3、ClassPathBeanDefinitionScanner

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
  /**
     * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
     * using the given {@link Environment} when evaluating bean definition profile metadata.
     * @param registry the {@code BeanFactory} to load bean definitions into, in the form
     * of a {@code BeanDefinitionRegistry}
     * @param useDefaultFilters whether to include the default filters for the
     * {@link org.springframework.stereotype.Component @Component},
     * {@link org.springframework.stereotype.Repository @Repository},
     * {@link org.springframework.stereotype.Service @Service}, and
     * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
     * @param environment the Spring {@link Environment} to use when evaluating bean
     * definition profile metadata
     * @param resourceLoader the {@link ResourceLoader} to use
     *
     * 为给定的bean工厂创建一个新的{@code ClassPathBeanDefinitionScanner},
     * 并在计算bean定义概要文件元数据时使用给定的{@link Environment}。
     * @param registry 以{@code BeanDefinitionRegistry}的形式将bean定义加载到{@code BeanFactory}
     * @param useDefaultFilters 是否包含
     * {@link org.springframework.stereotype.Component@Component}、
     * {@link org.springframework.stereotype.Repository@Repository}、
     * {@link org.springframework.stereotype.Service@Service}和
     * {@link org.springframework.stereotype.Controller@Controller}构造型批注的默认筛选器
     * @param environment 在计算bean定义概要文件元数据时使用的Spring{@link Environment}
     * @param resourceLoader 要使用的{@link ResourceLoader}
     *
     * @since 4.3.6
     */
    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
            Environment environment, @Nullable ResourceLoader resourceLoader) {

        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        //关键代码,Spring 内部默认为true
        //使用默认的Filters
        if (useDefaultFilters) {
            registerDefaultFilters();
        }
        setEnvironment(environment);
        setResourceLoader(resourceLoader);
    }
}

ClassPathBeanDefinitionScanner故名思义,是专门用于扫描类并将符合条件的类注册为BeanDefinition的工具对象。

ClassPathBeanDefinitionScanner构造函数的三个参数:

  1. registry(BeanDefinitionRegistry):
  2. useDefaultFilters(boolean):用于判断是否使用默认的注解过滤器(AnnotationTypeFilter)
    1. 注解过滤器/AnnotationTypeFilter:用于处理特定注解,有黑名单和白名单,先执行黑名单
      1. 黑名单/excludeFilters:标记该注解的类将不会被解析成Bean,即使在白名单中存在
      2. 白名单/includeFilters:标记该注解的类将会被解析成Bean
  3. environment(Environment):
  4. resourceLoader(ResourceLoader):资源加载器,这里先不做描述
    1. 这里资源加载器指的是AnnotationConfigApplicationContext对象
    2. 继承实现链为
      • AnnotationConfigApplicationContext—>
      • DefaultResourceLoader—>
      • GenericApplicationContext—>
      • AbstractApplicationContext—>
      • DefaultResourceLoader—>
      • ResourceLoader

构造函数初始化的过程:

1. 持有一个BeanDefinitionRegistry/bean对象(定义的注册器)
2. 判断是否使用默认的注解过滤器AnnotationTypeFilter.class,默认为是,如果是将注册以下注解
    1. 白名单:@Component,@ManagedBean,@Named
    2. 黑名单:无
3. 持有Environment对象
4. 通过resourceLoader对象生成对应的对象被ClassPathBeanDefinitionScanner持有,暂时不解析以下类
    1. resourcePatternResolver(ResourcePatternResolver):新建PathMatchingResourcePatternResolver对象
    2. metadataReaderFactory(MetadataReaderFactory):新建CachingMetadataReaderFactory对象
    3. componentsIndex(CandidateComponentsIndex):利用resourceLoader的类加载器新建CandidateComponentsIndex对象

总结

在实例化AnnotationConfigApplicationContext对象的时候,做了三件事情:

  1. 新建一个AnnotatedBeanDefinitionReader对象用于注册一个类到容器中,而一般我们注册的类通常是配置类;
  2. 同时注册几个BeanFactory后置处理器到容器中;
  3. 新建一个ClassPathBeanDefinitionScanner对象用于扫描和注册类中。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容