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

这张图是最最简单的处理流程图,其中还省略了初始化国际化、事件广播器等流程;下面参照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名称重复

 

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    // 是否允许覆盖重复bean定义
    if (this.allowBeanDefinitionOverriding != null) {
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    // 是否允许循环依赖
    if (this.allowCircularReferences != null) {
        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
}

 

spring有如下的行为:如果一个bean配置文件中存在两个及以上id或者name相同的bean,name直接抛出异常;如果不同配置文件中存在两个及以上id或者name相同的bean,默认会进行覆盖处理(可配置);

bean重复定义检查的流程在BeanFactory解析BeanDefination中,至于循环依赖,在另外的文章中说明。

不允许bean重复简单示例

public static void main(String[] args) {
    MyAbstractApplicationContext applicationContext = new MyAbstractApplicationContext("classpath:bean5.xml", "classpath:bean6.xml");

    applicationContext.setAllowBeanDefinitionOverriding(false);

    applicationContext.refresh();

    Name name = (Name) applicationContext.getBean("name");

    log.info(name.toString());
}

运行结果:

 

5、prepareBeanFactory

BeanFactory的准备阶段,这块没细看,只是知道忽略了生命周期相关接口的bean定义

6、postProcessBeanFactory

钩子方法,由子类实现;该方法用于在BeanFactory创建后对BeanFactory做一些定制化,如忽略某些接口的自动装配

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

 

posted @ 2020-07-03 18:12  光头用沙宣  阅读(156)  评论(0编辑  收藏  举报