Spring IoC原理(三) 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());
}
}
// 替换PropertySources
initPropertySources();
// 验证属性
getEnvironment().validateRequiredProperties();
// 存储预刷新的事件监听器
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// 将本地应用监听器重置为预刷新状态
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// 当multicaster启用时,允许将应用启动之间的事件进行发布
this.earlyApplicationEvents = new LinkedHashSet<>();
}
二、initPropertySources()
首先先来看一下initPropertySources()方法的源码,从源码中可以看到注明对于子类默认情况下不执行任何操作,但可以发现该方法被三个子类进行重写,如图2-1所示。要了解initPropertySources()方法的作用,先要了解什么是PropertySource。
/**
* 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() {
// For subclasses: do nothing by default.
}
![](http://tva1.sinaimg.cn/large/006KQSD7ly1h47nioa73pj30p402jq60.jpg)
为了便于操作PropertySource对象,Spring中有PropertySources接口与MutablePropertySources类,PropertySources提供了一个类型为PropertySource的迭代器,提供了一些MutablePropertySources在PropertySources基础上进行了功能上的扩展, 提供一些类似add、replace方法。
public abstract class PropertySource<T> {
protected final Log logger = LogFactory.getLog(getClass());
protected final String name;
protected final T source;
public PropertySource(String name, T source) {
Assert.hasText(name, "Property source name must contain at least one character");
Assert.notNull(source, "Property source must not be null");
this.name = name;
this.source = source;
}
// 省略部分代码
public static class StubPropertySource extends PropertySource<Object> {
public StubPropertySource(String name) {
super(name, new Object());
}
@Override
@Nullable
public String getProperty(String name) {
return null;
}
}
static class ComparisonPropertySource extends StubPropertySource {
private static final String USAGE_ERROR =
"ComparisonPropertySource instances are for use with collection comparison only";
public ComparisonPropertySource(String name) {
super(name);
}
@Override
public Object getSource() {
throw new UnsupportedOperationException(USAGE_ERROR);
}
@Override
public boolean containsProperty(String name) {
throw new UnsupportedOperationException(USAGE_ERROR);
}
@Override
@Nullable
public String getProperty(String name) {
throw new UnsupportedOperationException(USAGE_ERROR);
}
}
}
三、validateRequiredProperties()
在调用validateRequiredProperties()首先调用getEnvironment()方法,可以看一下getEnvironment()方法的源码,若当前环境为空则创建一个标准环境StandardEnvironment,然后将返回当前环境。
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
接着调用返回的环境StandardEnvironment基类AbstractEnvironment中的validateRequiredProperties()方法进行属性验证。在上下文环境创建前可通过ConfigurablePropertyResolver的setRequiredProperties()方法对必要属性进行设置并存储在requiredProperties中,validate RequiredProperties()方法会遍历requiredProperties中的所有属性检测是否进行相应的设置,若存在未设置的属性则会抛出异常。
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;
}
}