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对象用于扫描和注册类中。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容