Spring PropertyPlaceholderHelper(占位符解析器)
1. PropertyPlaceholderHelper作用: 将字符串里的占位符内容,用我们配置的properties里的替换。这个是一个单纯的类,没有继承没有实现,而且也没简单,没有依赖Spring框架其他的任何类。个人感觉自己项目中可以拿来模仿用。
我们解析的过程:
1、这里先贴一下Spring框架里的全部代码
2、分块解析
3、跑测试看结果,加深理解
2. 分块解析 下面这个是PropertyPlaceholderHelper占位解析的主要入口。其大致的过程是将占位的内容一块一块地取下来,通过递归将最内层的占位符先替换掉,然后跳出来替换外面的占位符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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" ); } placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); 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 ) { 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) { 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 ; } } System.out.println("enter..." + result); return result.toString(); }
下面这个方法是用来寻找占位符后缀索引的,需要注意的是withinNestedPlaceholder这个参数控制当我们获取到占位符后缀的时候是选择直接返回还是继续去获取占位符后缀。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 private int findPlaceholderEndIndex (CharSequence buf, int startIndex) { int index = startIndex + this .placeholderPrefix.length(); int withinNestedPlaceholder = 0 ; while (index < buf.length()) { if (substringMatch(buf, index, this .placeholderSuffix)) { if (withinNestedPlaceholder > 0 ) { withinNestedPlaceholder--; index = index + this .placeholderSuffix.length(); } else { return index; } } else if (substringMatch(buf, index, this .simplePrefix)) { withinNestedPlaceholder++; index = index + this .simplePrefix.length(); } else { index++; } } return -1 ; }
下面这个方法是用来判断str在index索引位置是否和substring匹配。
1 2 3 4 5 6 7 8 9 private boolean substringMatch (CharSequence str, int index, CharSequence substring) { for (int j = 0 ; j < substring.length(); j++) { int i = index + j; if (i >= str.length() || str.charAt(i) != substring.charAt(j)) { return false ; } } return true ; }
3、测试 test01.properties:
1 2 3 4 name=wangzha age=18 sex=man name18man=love
main方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Test public void testPlace () throws Exception { String a = "{name}{age}{sex}" ; String b = "{name{age}{sex}}" ; PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("{" , "}" ); InputStream in = new BufferedInputStream(new FileInputStream(ResourceUtils.getFile("classpath:test01.properties" ))); ; Properties properties = new Properties(); properties.load(in); System.out.println("替换前:" + a); System.out.println("替换后:" + propertyPlaceholderHelper.replacePlaceholders(a, new PropertyPlaceholderHelper.PlaceholderResolver() { @Override public String resolvePlaceholder (String placeholderName) { String value = properties.getProperty(placeholderName); return value; } })); System.out.println("====================================================" ); System.out.println("替换前:" + b); System.out.println("替换后:" + propertyPlaceholderHelper.replacePlaceholders(b, new PropertyPlaceholderHelper.PlaceholderResolver() { @Override public String resolvePlaceholder (String placeholderName) { String value = properties.getProperty(placeholderName); return value; } })); }
测试结果: