环境准备

前言

环境准备是ApplicationContext扩展功能refresh函数中的第一个步骤,接下来我们就详细的看看准备了什么?

环境准备

prepareRefresh函数主要是做些准备工作,例如对系统属性及环境变量的初始化及验证。

protected void prepareRefresh() {
        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());
            }
        }

        // 留给子类覆盖
        initPropertySources();

        // 验证需要的属性文件是否都已经放入环境中
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

 最后的两句代码才是关键,代码中没有什么逻辑处理,initPropertySources是空方法,专门留给子类去实现扩展功能的,没有任何的逻辑。而getEnvironment().validateRequiredProperties也因为没有需要验证的属性而没有做任何处理,那这些函数有什么用呢?Spring中存在相信就一定有它的作用,我们先来探索下各个函数的作用。

(1)initPropertySources正符合Spring的开放式结构设计,给用户最大扩展Spring的能力。用户可以根据自身的需求重写initPropertySources方法,并在方法中进行个性化的属性处理及设置。

(2)validateRequiredProperties则是对属性进行验证,那么如何验证呢?举个小例子来帮助理解:

  假如现在有这样的一个需求,工程在运行过程中用到的某个设置(例如VAR)是从系统环境变量中取得的,而如果用户没有在系统环境变量中配置这个参数,那么工程可能不会工作。这一要求可能会有各种各样的解决办法,当然,在Spring中可以这样做,你可以直接修改Spring的源码,例如,修改ClassPathXmlApplicationContext。当然,最好的办法就是对源码进行扩展,可以自定义一个类:

public class MyClassPathApplicationContext extends ClassPathXmlApplicationContext {

    public MyClassPathApplicationContext(String... configLocation){
        super(configLocation);
    }

    @Override
    protected void initPropertySources() {
        //添加验证要求
        getEnvironment().setRequiredProperties("VAR");
    }
}

上述自定义的这个类继承自ClassPathXmlApplicationContext的MyClassPathApplicationContext,并重写了initPropertySources方法,在方法中我们添加了个性化的需求,那么在验证的时候也就是程序走到getEnvironment().validateRequiredProperties()代码的时候,如果系统并没有检测到对应VAR的环境变量,那么将会抛出异常。当然还有一步就是我们需要在使用的时候替换掉原有的ClassPathXmlApplicationContext:

public static void main(String[] args){
        ApplicationContext ac = new MyClassPathApplicationContext("spring-config.xml");
        User user = (User) ac.getBean("user");
        System.out.println(user.getName());
    }

如果环境中没有配置VAR变量,运行上述测试代码:

12月 28, 2018 9:38:07 下午 com.joe.applicant.MyClassPathApplicationContext prepareRefresh
信息: Refreshing com.joe.applicant.MyClassPathApplicationContext@5b87ed94: startup date [Fri Dec 28 21:38:07 CST 2018]; root of context hierarchy
Exception in thread "main" org.springframework.core.env.MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [VAR]
    at org.springframework.core.env.AbstractPropertyResolver.validateRequiredProperties(AbstractPropertyResolver.java:140)
    at org.springframework.core.env.AbstractEnvironment.validateRequiredProperties(AbstractEnvironment.java:512)
    at org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:591)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:512)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
    at com.joe.applicant.MyClassPathApplicationContext.<init>(MyClassPathApplicationContext.java:10)
    at com.joe.applicant.MyClassPathApplicationContext.main(MyClassPathApplicationContext.java:21)

发现报错,提示环境中没有VAR变量。

设置环境变量:因为LZ使用的是IDEA,所以这里先展示如何设置环境变量:

第一步:点击 Run ------->  Edit Configurations

第二步:点击 需要运行的类,在Environment variables 点击设置变量

 

第三步:设置对应变量

保存后。在运行上述测试代码:

十二月 29, 2018 10:40:21 上午 com.joe.mytag.application.MyClassPathApplicationContext prepareRefresh
信息: Refreshing com.joe.mytag.application.MyClassPathApplicationContext@5910e440: startup date [Sat Dec 29 10:40:21 CST 2018]; root of context hierarchy
十二月 29, 2018 10:40:21 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring.xml]
Joe

发现没有报错,成功运行。 

参考:《Spring源码深度解析》 郝佳 编著:

posted on 2018-12-29 10:47  AoTuDeMan  阅读(382)  评论(0编辑  收藏  举报

导航