Spring 的那点事 (二) —— initPropertySources() 个性化属性处理&设置

 2023-02-17
原文作者:憨憨的八戒 原文地址:https://juejin.cn/post/7025975596928745485

功能

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