#博学谷IT学习技术支持#
Spring IOC refresh()方法之 prepareRefresh()
上一节我们大体了解了一下Spring-IOC加载中的setConfigLocations()方法
Spring-IOC加载流程(1.setConfigLocations方法)
今天,我们开始看下refresh()方法中的prepareRefresh()方法
先来看下prepareRefresh()方法的内容
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.
// 初始化properties
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<>();
}
1.initPropertySources()
protected void initPropertySources() {
// For subclasses: do nothing by default.
}
跟进该方法,我们发现 AbstractApplicationContext 类中是空实现。该方法主要作用是加载上下文环境的属性源。就是将一些配置属性加载到Environment中。我们可以自定义一个类继承ClassPathXmlApplicationContext,并重写initPropertySources()方法
public class TestClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
@Override
protected void initPropertySources() {
MutablePropertySources propertySources = getEnvironment().getPropertySources();
Properties properties = new Properties();
FileInputStream fileInputStream = null;
try {
ClassLoader classLoader = this.getClassLoader();
String file = classLoader.getResource("application.properties").getFile();
fileInputStream = new FileInputStream(file);
properties.load(fileInputStream);
} catch (Exception e) {
e.printStackTrace();
}
// properties.setProperty("aaa", "aaa");
PropertiesPropertySource propertiesPropertySource = new PropertiesPropertySource("test", properties);
propertySources.addLast(propertiesPropertySource);
}
}
我们在initPropertySources()方法中去加载类路径下的applicaion.properties文件,并将文件的内容放在Environment中的propertySources属性中。
我们来看下加载后的数据
可以看到数据已经加载到了environment中了。
2.getEnvironment().validateRequiredProperties();
继续看下面的内容,getEnvironment().validateRequiredProperties()用来校验必需的properties,
被校验的属性需要在执行该方法执行使用environment.setRequiredProperties()方法赋值。
ClassPathXmlApplicationContext classPathXmlApplicationContext = new TestClassPathXmlApplicationContext();
ConfigurableEnvironment environment = classPathXmlApplicationContext.getEnvironment();
environment.setRequiredProperties("aaa");// 这里的aaa后续测试可以替换为其他的值
classPathXmlApplicationContext.setConfigLocation("classpath*:applicationContext.xml");
classPathXmlApplicationContext.refresh();
我们可以使用上面的代码来模拟设置必需校验的属性;
我们可以分别设置需要校验的属性为aaa和ccc,执行后可以看到aaa属性是存在的,因此校验成功,但是ccc属性不存在,因此校验失败。
//我们可以看到ccc属性校验失败抛出的异常信息
Exception in thread "main" org.springframework.core.env.MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [ccc]
3.存储监听器
prepareRefresh()方法中后续的操作是存储监听器。
// 使用addApplicationListener方法添加新的监听器
classPathXmlApplicationContext.addApplicationListener(new TestApplicationListener());
我们可以使用的addApplicationListener()方法来设置监听器。这里我们自定义一个监听器
// 自定义的监听器要实现ApplicationListener<E extent ApplicationEvent>接口,
// ApplicationEvent我们使用spring已经定义好的ContextClosedEvent
public class TestApplicationListener implements ApplicationListener<ContextClosedEvent> {
@Override
public void onApplicationEvent(ContextClosedEvent event) {
//内部为空实现
}
}
调用addApplicationListener()方法将监听器添加到上下文中。
我们可以看到监听器已经添加到了上下文中,后续会在不同的事件处理的时候调用相应的监听器。
关于监听器的调用,我们在后续章节中解析。