prepareRefresh()方法主要做了哪些事情,例如对系统属性及环境变量的初始化以及验证。
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
synchronized (this.activeMonitor) {
this.active = true;
}
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
// 留给子类实现
initPropertySources();
// Validate that all properties marked as required are resolvable
// 验证需要的属性文件是否都已经放入环境中
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
}
(1)设置active 为true,这就是一个很简单赋值。
(2)initPropertySources看似没做什么事情,这个正式符合Spring开放式结构设计,给用户最大的扩展能力。用户根据自己的需要重写initPropertySources方法,并在方法中进行个性化的属性处理及设置。
(3)validateRequiredProperties是对属性进行验证,那么如何验证呢?
假如:现在有一个需求,工程在运行过程中用到的某个设置(比如VAR)是从系统环境变量取得的,而如果用户没有在系统环境变量中配置这个参数,那么工程可能不会工作。这要求可能会有各种各样的解决方法,当然,在Spring中可以这么做,你可以直接修改Spring的源码,例如修改ClassPathXmlApplicationContext。当然,最好的办法还是对源码进行扩展,我们可以自定义类:
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
public MyClassPathXmlApplicationContext(String... configLocations) {
super(configLocations);
}
@Override
protected void initPropertySources() {
//super.initPropertySources();
getEnvironment().setRequiredProperty("VAR");
}
}
我们自定义了继承自ClassPathXmlApplicationContext的MyClassPathXmlApplicationContext,并重写了initPropertySources方法,在方法中添加了我们的个性化需求,那么在验证的时候也就是程序走到getEnvironment().validateRequiredProperties()代码的时候,如果系统没有检测到对应VAR的环境变量,那么就抛出异常。当然我们还需要在使用的时候替换掉原有的ClassPathXmlApplicationContext,代码如下:
public class TestAnimal3 {
public static void main(String[] args) {
ApplicationContext context = new MyClassPathXmlApplicationContext("applicationContext.xml");
Animal animal = (Animal) context.getBean("animal");
animal.say();
}
}
看看控制台输出:
2018-04-16 16:23:04,426 [main] INFO [com.feiniu.springframework.test.MyClassPathXmlApplicationContext org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:503)] - Refreshing com.feiniu.springframework.test.MyClassPathXmlApplicationContext@21b602b9: startup date [Mon Apr 16 16:23:04 GMT+08:00 2018]; root of context hierarchy
Exception in thread "main" java.lang.IllegalStateException: required key [VAR] not found
at org.springframework.core.env.AbstractPropertyResolver.getRequiredProperty(AbstractPropertyResolver.java:94)
at org.springframework.core.env.AbstractEnvironment.getRequiredProperty(AbstractEnvironment.java:444)
at com.feiniu.springframework.test.MyClassPathXmlApplicationContext.initPropertySources(MyClassPathXmlApplicationContext.java:16)
at org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:507)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:441)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at com.feiniu.springframework.test.MyClassPathXmlApplicationContext.<init>(MyClassPathXmlApplicationContext.java:9)
at com.feiniu.springframework.test.TestAnimal3.main(TestAnimal3.java:7)
从上述报错日志来看,required key [VAR] not found,找不到VAR变量,说明重写验证方法生效了。该功能可以运用到工作中的场景,在dev和beta环境配置文件都加了变量,由于开发人员疏忽,online环境配置漏了,此时测试人员验证功能也没覆盖到这段新增配置代码,就造成了online的bug。如果运用该功能,应用war包在online启动就会报错,以避免造成online的bug出现。