在Spring中有一个这样的工具方法parseStringValue(),比如在xml中的EL表达式解析,资源加载,@Value注解内容解析,都用到了这样一个工具类方法,今天我们就来看看这个方法的实现。
parseStringValue()
我们先来写一个main方法测试一下
public class SpringTest1_2 { private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<String, String>(4); static { wellKnownSimplePrefixes.put("}", "{"); wellKnownSimplePrefixes.put("]", "["); wellKnownSimplePrefixes.put(")", "("); } public static String placeholderPrefix = "${"; public static String placeholderSuffix = "}"; public static String simplePrefix = "{"; public static String valueSeparator = ":"; public static boolean ignoreUnresolvablePlaceholders = false; public static void main(String[] args) { String text = "${user}"; String a = parseStringValue(text, new PropertyPlaceholderHelper.PlaceholderResolver() { @Override public String resolvePlaceholder(String placeholderName) { if(placeholderName.equals("user")){ return "zhansan"; }else if (placeholderName.equals("{user}")){ return "xxx"; }else if(placeholderName.equals("zhansan")){ return "lisi"; }else if(placeholderName.equals("person")){ return "${person1}"; }else if (placeholderName.equals("person1")){ return "${person}"; }else if(placeholderName.equals("lisi")){ return "wangwu"; } return null; } },new HashSet()); System.out.println(a); } // ${${user}} // ${user} public static String parseStringValue(String strVal, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver, Set visitedPlaceholders) { StringBuilder result = new StringBuilder(strVal); int startIndex = strVal.indexOf(placeholderPrefix); while (startIndex != -1) { // 查找和当前 前缀(${)相匹配 后缀(})的index,比如 ${${user}} int endIndex = findPlaceholderEndIndex(result, startIndex); if (endIndex != -1) { String placeholder = result.substring(startIndex + placeholderPrefix.length(), endIndex); String originalPlaceholder = placeholder; if (!visitedPlaceholders.add(originalPlaceholder)) { // ${${person}} 避免循环依赖 throw new IllegalArgumentException( "Circular placeholder reference '" + originalPlaceholder + "' in property definitions"); } // 递归调用,获取 ${} 内的内容,比如${${user}} ,第一次执行 parseStringValue 方法变成${user},再一次执行parseStringValue 方法,得到user placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); // 由上面得到的值调用resolvePlaceholder方法得到具体的值 zhansan String propVal = placeholderResolver.resolvePlaceholder(placeholder); if (propVal == null && valueSeparator != null) { // 如果要执行下面的情况,如下配置 ${user1:wangwu} 先解析得到 user1:wangwu ,通过user1:wangwu 找不到对应的值 // 那么通过 : 分隔,得到array[0]=user1 ,array[1] 是wangwu ,再通过user1 去解析,如果解析不到,则使用Array[1]作为 // 默认值 int separatorIndex = placeholder.indexOf(valueSeparator); if (separatorIndex != -1) { String actualPlaceholder = placeholder.substring(0, separatorIndex); String defaultValue = placeholder.substring(separatorIndex + valueSeparator.length()); propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder); if (propVal == null) { propVal = defaultValue; } } } if (propVal != null) { // 对于正常情况都会走到下面来 ${user} propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); result.replace(startIndex, endIndex + placeholderSuffix.length(), propVal); startIndex = result.indexOf(placeholderPrefix, startIndex + propVal.length()); } else if (ignoreUnresolvablePlaceholders) { startIndex = result.indexOf(placeholderPrefix, endIndex + placeholderSuffix.length()); } else { throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'" + " in string value \"" + strVal + "\""); } visitedPlaceholders.remove(originalPlaceholder); } else { startIndex = -1; } } return result.toString(); } public static int findPlaceholderEndIndex(CharSequence buf, int startIndex) { int index = startIndex + placeholderPrefix.length(); int withinNestedPlaceholder = 0; while (index < buf.length()) { if (StringUtils.substringMatch(buf, index, placeholderSuffix)) { if (withinNestedPlaceholder > 0) { withinNestedPlaceholder--; index = index + placeholderSuffix.length(); } else { return index; } } else if (StringUtils.substringMatch(buf, index, simplePrefix)) { withinNestedPlaceholder++; index = index + simplePrefix.length(); } else { index++; } } return -1; } }
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) { return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() { @Override public String resolvePlaceholder(String placeholderName) { return getPropertyAsRawString(placeholderName); } }); } public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) { return parseStringValue(value, placeholderResolver, new HashSet()); } protected abstract String getPropertyAsRawString(String key);
Spring在外部调用了doResolvePlaceholders方法传入了要解析的字符串 text ,以及PropertyPlaceholderHelper,返回了PropertyPlaceholderHelper类的replacePlaceholders方法调用,replacePlaceholders方法调用过程中传入解析的字符串 text及PlaceholderResolver接口实现类,replacePlaceholders方法内部调用了parseStringValue方法,PlaceholderResolver接口实现类实现resolvePlaceholder方法,而resolvePlaceholder方法内部调用了抽象方法getPropertyAsRawString,他将调用子类的getPropertyAsRawString方法,因此在parseStringValue()方法内部回调resolvePlaceholder方法时,实际上是调用子类的getPropertyAsRawString()方法。Spring通过将简单功能巧妙组合,从而保证代码的灵活性,可扩展性。
Spring 每次像剥洋葱一样,一层一层往里剥,直到最里层,就使用placeholderResolver的resolvePlaceholder方法解析相应的值,而内部根据外层传入进来的placeholderResolver不同,从而调用不同的resolvePlaceholder方法。整个过程正如颜色的叠加,最里层的红色+外层绿色=黄色 ,黄色+蓝色=白色。如${{红色}}} = 白色
,通过代码巧妙组合,既达到代码的公用,又保证了代码灵活。