码迷,mamicode.com
首页 > 编程语言 > 详细

spring学习总结002 --- IOC容器启动源码(简易版)

时间:2020-07-03 19:09:19      阅读:61      评论:0      收藏:0      [点我收藏+]

标签:响应   ges   factory   XML   exce   finish   监听器   读取   linked   

技术图片

这张图是最最简单的处理流程图,其中还省略了初始化国际化、事件广播器等流程;下面参照ClassPathXmlApplicationContext源码,记录下IOC容器启动的大致流程:

1、ClassPathXmlApplicationContext构造器

public ClassPathXmlApplicationContext(
        String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
        throws BeansException {

    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}

先为IOC容器设置了配置文件路径,然后执行IOC启动最核心的方法:refresh()

2、refresh方法

refresh方法实现位于ClassPathXmlApplicationContext的父类AbstractApplicationContext,主要有如下几个功能:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 容器刷新的准备工作
        prepareRefresh();

        // 创建BeanFactory, 读取配置文件中bean的定义
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 对BeanFactory进行初始化
        prepareBeanFactory(beanFactory);

        try {
            // 钩子方法, 子类进行扩展
            postProcessBeanFactory(beanFactory);

            // 执行BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册BeanPostProcessor
            registerBeanPostProcessors(beanFactory);

            // 初始化国际化信息
            initMessageSource();

            // 初始化事件广播器
            initApplicationEventMulticaster();

            // 钩子方法, 子类进行扩展
            onRefresh();

            // 注册事件监听器
            registerListeners();

            // 初始化单例bean(未配置lazz-init)
            finishBeanFactoryInitialization(beanFactory);

            // 容器启动最后一步: 事件推送
            finishRefresh();
        }
    }
}

3、prepareRefresh方法

protected void prepareRefresh() {
    // 设置启动时间和启动标记
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);
    
    // 钩子方法, 用户自行实现初始化属性
    initPropertySources();

    // 验证所有必要属性, 必要属性来源:
    // 1、ConfigurablePropertyResolver#setRequiredProperties
    // 2、用户扩展的initPropertySources
    getEnvironment().validateRequiredProperties();

    // 允许应用启动之前的事件,当multicaster一旦可用的时候,可用立刻响应发布的事件。
    this.earlyApplicationEvents = new LinkedHashSet<>();
}

里面有一个钩子方法,由子类实现其功能;我在实际项目中使用initPropertySources,强制要求某些环境变量必须存在

示例:

public class MyAbstractApplicationContext extends ClassPathXmlApplicationContext {

    public MyAbstractApplicationContext(String configLocation) throws BeansException {
        super(configLocation);
    }

    @Override
    protected void initPropertySources() {
        super.initPropertySources();

        // 设置TEST_ENV环境变量为必要的, 如果没有, IOC容器启动失败
        getEnvironment().setRequiredProperties("TEST_ENV");
    }
}

运行结果:

技术图片

4、obtainFreshBeanFactory方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 创建BeanFactory, 然后解析并保存Bean定义
    refreshBeanFactory();

    // 返回BeanFactory
    return getBeanFactory();
}
protected final void refreshBeanFactory() throws BeansException {
    // 存在BeanFactory, 先销毁
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 创建BeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        // 定制BeanFactory, 根据Application的配置, 决定BeanFactory是否允许重复依赖和Bean名称重复
        customizeBeanFactory(beanFactory);
        // 解析并保存Bean定义信息
        // 保存在DefaultListableBeanFactory.beanDefinitionMap
        loadBeanDefinitions(beanFactory);
        // 设置为全局BeanFactory
        this.beanFactory = beanFactory;
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

customizeBeanFactory方法可以为BeanFactory设置是否允许bean循环依赖以及是否允许bean名称重复

spring学习总结002 --- IOC容器启动源码(简易版)

标签:响应   ges   factory   XML   exce   finish   监听器   读取   linked   

原文地址:https://www.cnblogs.com/sniffs/p/13229969.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!