Spring加載流程源碼分析02【setConfigLocations】 setConfigLocations

上篇文章介紹了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;
    }
}

  1. setConfigLocations主要工作有兩個:創建環境對象ConfigurableEnvironment 、處理ClassPathXmlApplicationContext傳入的字符串中的佔位符;
  2. 環境對象ConfigurableEnvironment中包含了當前JVM的profile配置信息、環境變量、 Java進程變量;
  3. 處理佔位符的關鍵是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;
}

提供的方法中可以看出兩個功能

  1. 處理profile:Profile是對測試、生產等不同環境下的bean配置,這裏我們沒有特別設置,所以用到的profile是AbstractEnvironment的defaultProfiles; 之前介紹IOC的時候也介紹過profile。
  2. 處理property
  3. 獲取系統環境信息
  4. 合併環境信息

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();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章