前面提到了ApplicationContext的实例化过程,实例化的时候会判断refresh标志,一般都是true的,在refresh方法中,第一个执行的方法就是prepareRefresh,今天一起看下这个方法内部都做了什么。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 准备Context的刷新
prepareRefresh();
....
}
}
prepareRefresh方法分析
- 首先看下ApplicationContext中的prepareRefresh方法内部。
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
* 准备刷新,设置应用开启的时间还有active标志,并且执行一些属性源的初始化工作
*/
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
// 初始化placeholder属性
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
// 验证所有的必须的属性。
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
// 允许应用启动之前的事件,当multicaster一旦可用的时候,可用立刻响应发布的事件。
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
-
initPropertySources,在应用启动之前替换一些属性占位符,这个方法再Spring的对象中一般都没有实现,应该是用来方便我们后期扩展使用的方法。
-
validateRequiredProperties,Environment类的方法验证必须的属性是否正确。
// AbstractEnvironment 类
//private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
// private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
this.propertyResolver.validateRequiredProperties();
}
validateRequiredProperties代码分析
- 首先看方法内部。
// this.requiredProperties如果没有操作默认是空的LinkedList
// private final Set<String> requiredProperties = new LinkedHashSet<String>();
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;
}
}
- PropertyResolver.getProperty
// PropertySourcesPropertyResolver类
@Override
public String getProperty(String key) {
return getProperty(key, String.class, true);
}
// 获取属性内部真正起作用的方法
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
//打日志
if (logger.isTraceEnabled()) {
logger.trace(String.format("getProperty(\"%s\", %s)", key, targetValueType.getSimpleName()));
}
// this.propertySources上面提到了,传进来的是个new MutablePropertySources(this.logger),可变的属性源
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
Object value;
// 从propertySource.getProperty中获取对应的key,并且进行解析
if ((value = propertySource.getProperty(key)) != null) {
Class<?> valueType = value.getClass();
// 解析字符串类型的key
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
// this.conversionService.canConvert转换获取的value
if (!this.conversionService.canConvert(valueType, targetValueType)) {
throw new IllegalArgumentException(String.format(
"Cannot convert value [%s] from source type [%s] to target type [%s]",
value, valueType.getSimpleName(), targetValueType.getSimpleName()));
}
return this.conversionService.convert(value, targetValueType);
}
}
}
if (debugEnabled) {
logger.debug(String.format("Could not find key '%s' in any property source. Returning [null]", key));
}
return null;
}
可以看出PropertySourcesPropertyResolver获取key的过程是
- 先通过PropertySource获取value
- 再通过conversionService转换value为目标类型,默认是转换为String的是没有问题的。如果无法转换抛出异常
小结
ApplicationContext的准备刷新prepareRefresh逻辑不多,相对简单一些。不过其中涉及到的解析property的过程需要了解。
其它类
- PropertyPlaceholderHelper ,parseStringValue方法
最后
一步一步来. 看似慢的方法也许是能最快实现目标的方法。
网友评论