1.方法代码如下:
/**
* 准备工作
*/
protected void prepareRefresh() {
//记录初始化开始时间
this.startupDate = System.currentTimeMillis();
this.closed.set(false); //context是否关闭的标志,设置为false
this.active.set(true); //context是否激活的标志,设置为true
if (logger.isDebugEnabled()) { //记录日志
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
//留给子类实现的空方法
initPropertySources();
/** AbstractPropertyResolver类的requiredProperties是个集合,
* 在下面的validateRequiredProperties方法中,都要拿requiredProperties中的元素作为key去检查是否存在对应的环境变量,
* 如果不存在就抛出异常
*/
getEnvironment().validateRequiredProperties();
// 初始化earlyApplicationListeners容器 --LinkedHashSet
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// 清空applicationListeners容器 并将earlyApplicationListeners中的数据全部添加进来
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// 初始化earlyApplicationEvents容器 --LinkedHashSet
this.earlyApplicationEvents = new LinkedHashSet<>();
}
涉及到的各个属性定义如下:
private long startupDate;
/** context是否激活的标志 */
private final AtomicBoolean active = new AtomicBoolean();
/** context是否关闭的标志 */
private final AtomicBoolean closed = new AtomicBoolean();
@Nullable
private Set<ApplicationListener<?>> earlyApplicationListeners;
/** Statically specified listeners. */
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
/** Statically specified listeners. */
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
@Nullable
private Set<ApplicationEvent> earlyApplicationEvents;
2.initPropertySources
这是一个留给子类实现的空方法,我们使用时可以重写该方法,在容器启动前,添加一些自定义校验或者进行其他处理,原方法代码如下:
/**
* <p>Replace any stub property sources with actual instances.
* @see org.springframework.core.env.PropertySource.StubPropertySource
* @see org.springframework.web.context.support.WebApplicationContextUtils#initServletPropertySources
*/
protected void initPropertySources() {
}
2.1 initPropertySources使用举例
1.我们可以自定义一个类继承ClassPathXmlApplicationContext,并重写initPropertySources方法,代码如下:
/**
* 自定义一个容器启动类继承ClassPathXmlApplicationContext 并重写其initPropertySources方法
*/
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
public MyClassPathXmlApplicationContext(String string) {
super(string);
}
@Override
public void initPropertySources(){
ConfigurableEnvironment env = getEnvironment();
env.setRequiredProperties("Path");
String property = env.getRequiredProperty("Path");
//打印,方便观察
Stream.of(property.split(";")).filter(x -> x.toUpperCase().contains("JAVA\\JDK")).forEach(System.out::println);
}
}
2.写一个小demo用我们自定义的类启动容器。
public class Demo {
public static void main(String[] args) {
MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("spring.xml");
}
}
3.在容器启动时,控制台会多打印如下图:
3.getEnvironment与validateRequiredProperties详解
1.getEnvironment
/**
* 获取环境属性
*/
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
// 1.创建Environment
this.environment = createEnvironment();
}
return this.environment;
}
/**
* 创建Environment
*/
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
2.validateRequiredProperties
@Override
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
for (String key : this.requiredProperties) {
if (this.getProperty(key) == null) {
ex.addMissingRequiredProperty(key);
}
}
if (!ex.getMissingRequiredProperties().isEmpty()) {
throw ex;
}
}
注:validateRequiredProperties方法的代码实现位于AbstractPropertyResolver类中