上篇文章介紹了Spring源碼中的三步中的super(parent)的代碼,本文介紹下setConfigLocations(configLocation)方法
類圖
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
// 1.初始化父類
super(parent);
// 2.設置本地的配置信息
setConfigLocations(configLocations);
// 3.完成Spring容器的初始化
if (refresh) {
refresh();
}
}
setConfigLocations
public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//循環取出每一個path參數,在此處就一個“applicationContext.xml“”
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
- setConfigLocations主要工作有兩個:創建環境對象ConfigurableEnvironment 、處理ClassPathXmlApplicationContext傳入的字符串中的佔位符;
- 環境對象ConfigurableEnvironment中包含了當前JVM的profile配置信息、環境變量、 Java進程變量;
- 處理佔位符的關鍵是ConfigurableEnvironment、PropertyResolver、PropertyPlaceholderHelper之間的配合
// 這個方法的目的是替換掉path字符串中的佔位符${XXX}這樣的內容
protected String resolvePath(String path) {
// 1.進入getEnvironment()
// 2.進入resolveRequiredPlaceholders方法
return getEnvironment().resolveRequiredPlaceholders(path);
}
1.ConfigurableEnvironment
getEnvironment():創建了ConfigurableEnvironment 對象
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
提供的方法中可以看出兩個功能
- 處理profile:Profile是對測試、生產等不同環境下的bean配置,這裏我們沒有特別設置,所以用到的profile是AbstractEnvironment的defaultProfiles; 之前介紹IOC的時候也介紹過profile。
- 處理property
- 獲取系統環境信息
- 合併環境信息
2.PropertyResolver
resolveRequiredPlaceholders(path)
處理佔位符的方法
3.PropertyPlaceholderHelper
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
if (this.strictHelper == null) {
// 創建PropertyPlaceholderHelper對象
this.strictHelper = createPlaceholderHelper(false);
}
return doResolvePlaceholders(text, this.strictHelper);
}
進入doResolvePlaceholders繼續查看
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {
@Override
public String resolvePlaceholder(String placeholderName) {
//
return getPropertyAsRawString(placeholderName);
}
});
}
getPropertyAsRawString的具體實現在PropertySourcesPropertyResolver類中
@Override
protected String getPropertyAsRawString(String key) {
return getProperty(key, String.class, false);
}
繼續跟蹤helper.replacePlaceholders(),到了PropertyPlaceholderHelper.parseStringValue方法,這裏面逐一找出每個佔位符去做替換:
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
Assert.notNull(value, "'value' must not be null");
return parseStringValue(value, placeholderResolver, new HashSet<String>());
}
parseStringValue方法中,找到了佔位符後,會調用入參placeholderResolver的resolvePlaceholder(placeholder)方法,也就是上面匿名類的getPropertyAsRawString方法(實際上就是PropertySourcesPropertyResolver.getPropertyAsRawString方法),最終會在PropertySourcesPropertyResolver.getProperty方法中找出所有的屬性來匹配佔位符
protected String parseStringValue(
String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
StringBuilder result = new StringBuilder(strVal);
int startIndex = strVal.indexOf(this.placeholderPrefix);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// Recursive invocation, parsing placeholders contained in the placeholder key.
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isTraceEnabled()) {
logger.trace("Resolved placeholder '" + placeholder + "'");
}
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new IllegalArgumentException("Could not resolve placeholder '" +
placeholder + "'" + " in string value \"" + strVal + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return result.toString();
}