Spring的那点事(二)——initPropert

这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

功能

prepareRefresh() 该方法为 refresh() 中的一个方法。

功能为以下几点

  • 设置容器启动时间
  • 设置 closed 和 active 两个标识位
  • 初始化系统属性资源
  • 获取 Environment 对象,校验属性值并赋值到 Environment 对象中
  • 准备监听器和事件监听器

代码

package org.springframework.context.support

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean {
     
    protected void prepareRefresh() {
        // Switch to active.
        // 设置容器启动的时间
        this.startupDate = System.currentTimeMillis();
        // 容器的关闭标志位
        this.closed.set(false);
        // 容器的激活标志位
        this.active.set(true);

        // 记录日志
        if (logger.isDebugEnabled()) {
            if (logger.isTraceEnabled()) {
                logger.trace("Refreshing " + this);
            }
            else {
                logger.debug("Refreshing " + getDisplayName());
            }
        }

        // Initialize any placeholder property sources in the context environment.
        // 留给子类覆盖,初始化属性资源
        initPropertySources();

        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
        // 创建并获取环境对象,验证需要的属性文件是否都已经放入环境中
        getEnvironment().validateRequiredProperties();

        // Store pre-refresh ApplicationListeners...
        // 判断刷新前的应用程序监听器集合是否为空,如果为空,则将监听器添加到此集合中
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        }
        else {
            // Reset local application listeners to pre-refresh state.
            // 如果不等于空,则清空集合元素对象
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        // 创建刷新前的监听事件集合
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }
    
    protected void initPropertySources() {
    }
}
复制代码

扩展 initPropertySources()

Spring的强大之处不仅仅在于它为Java开发者提供了极大便利,而且在于它的开放式架构,使得用户可以拥有最大扩展 Spring 的能力。其中,initPropertySources() 方法就是一个例子。

可以看到 prepareRefresh() 中的 initPropertySources() 方法并没有任何参数,而如果进入initPropertySources() 方法内部,也会发现该方法是空的,没有任何逻辑。

Spring之所这样设计,就是为了让用户根据自己的需要,可以重写 initPropertySources() 方法,并在方法中进行个性化的属性处理以及设置。

举例

我们可以继承此类或其子类来重写initPropertySources方法,实现一些扩展。此处我们做了两个扩展:

  • 向Environment中添加了一个属性值。
  • 我们设置了一个必要的系统属性username,当Environment中不包含username属性时系统会抛出异常。
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

    public MyClassPathXmlApplicationContext(String... configLocations){
        super(configLocations);
    }

    @Override
    protected void initPropertySources() {
        System.out.println("扩展initPropertySource");
        
        //这里添加了一个name属性到Environment里面,以方便我们在后面用到
        getEnvironment().getSystemProperties().put("name","bobo");
        
        //这里要求Environment中必须包含username属性,如果不包含,则抛出异常
        getEnvironment().setRequiredProperties("username");
    }
}
复制代码