白小姐彩图 www.5vq5o.cn Spring为我们提供了一个PropertyPlaceholderConfigurer,它能够使Bean在配置时引用外部属性文件。
可以将BeanFactory定义中的一些属性值放到另一个单独的标准Java Properties文件中。
我们在部署应用时只需要在属性文件中对一些属性进行修改,而不用对主XML定义文件或容器所用文件进行复杂和危险的修改。
让我们看看下面的例子片段:














jdbc.properties:




相信上面的配置大家都用到过,
如此配置后 xml 文件中的 "${***}"占位符会被替换成jdbc.properties中对应的属性值。
现在我有一个需求,要求在DB中配置一些参数,如数据库的用户名、密码等,我在参数中提供一个模板,
形如 jdbc:oracle:thin:@${host}:${port:1521}:${service_name}。
然后host、port、service_name从参数表中取得,然后进行替换。
于是,我想到了Spring为我们提供的PropertyPlaceholderConfigurer.java,在看了代码之后,将字符串替换的代码摘出来,为我的需求服务。
下面是我摘出来的字符串解析替换的辅助类:
- import java.util.HashSet;
- import java.util.Map;
- import java.util.Set;
- import org.springframework.util.StringUtils;
- public class PlaceholderUtils {
- /** *//** Default Holder prefix: "${" */
- public static final String DEF_HOLDER_PREFIX = "${";
- public static final int DEF_HOLDER_PREFIX_LEN = 2;
- /** *//** Default Holder suffix: "}" */
- public static final String DEF_HOLDER_SUFFIX = "}";
- public static final int DEF_HOLDER_SUFFIX_LEN = 1;
- /** *//** Never check system properties. */
- public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0;
- /** *//**
- * Check system properties if not resolvable in the specified properties.
- * This is the default.
- */
- public static final int SYS_PROPS_MODE_FALLBACK = 1;
- /** *//**
- * Check system properties first, before trying the specified properties.
- * This allows system properties to override any other property source.
- */
- public static final int SYS_PROPS_MODE_OVERRIDE = 2;
- /** *//**
- * Parse the given String value recursively, to be able to resolve
- * nested Holders (when resolved property values in turn contain
- * Holders again).
- *
- * @param strVal
- * the String value to parse
- * @param props
- * the Properties to resolve Holders against
- * @param visitedHolders
- * the Holders that have already been visited
- * during the current resolution attempt (used to detect circular references
- * between Holders). Only non-null if we're parsing a nested Holder.
- * @throws Exception
- * @throws AppException
- * if invalid values are encountered
- * @see #resolveHolder(String, java.util.Properties, int)
- */
- public static String parse(String strVal) throws Exception {
- Set<String> visitedHolders = new HashSet<String>();
- return parse(strVal, null, visitedHolders, false);
- }
- public static String parse(String strVal, Map<Object, Object> props) throws Exception {
- Set<String> visitedHolders = new HashSet<String>();
- return parse(strVal, props, visitedHolders, false);
- }
- public static String parse(String strVal, boolean ignoreBadHolders) throws Exception {
- Set<String> visitedHolders = new HashSet<String>();
- return parse(strVal, null, visitedHolders, ignoreBadHolders);
- }
- private static String parse(String strVal, Map<Object, Object> props,
- Set<String> visitedHolders, boolean ignoreBadHolders) throws Exception {
- StringBuffer buf = new StringBuffer(strVal);
- int startIndex = strVal.indexOf(DEF_HOLDER_PREFIX);
- while (startIndex != -1) {
- int endIndex = findHolderEndIndex(buf, startIndex);
- if (endIndex != -1) {
- String holder = buf.substring(startIndex + DEF_HOLDER_PREFIX_LEN, endIndex);
- String defValue = null;
- int defIndex = org.apache.commons.lang.StringUtils.lastIndexOf(holder, ":");
- if (defIndex >= 0) {
- defValue = StringUtils.trimWhitespace(holder.substring(defIndex + 1));
- holder = StringUtils.trimWhitespace(holder.substring(0, defIndex));
- }
- if (!visitedHolders.add(holder)) {
- throw new Exception("Circular PlaceHolder reference '" + holder
- + "' in property definitions");
- }
- // Recursive invocation, parsing Holders contained in the Holder key.
- holder = parse(holder, props, visitedHolders, ignoreBadHolders);
- // Now obtain the value for the fully resolved key
- String propVal = resolveHolder(holder, props, SYS_PROPS_MODE_FALLBACK, defValue);
- if (propVal != null) {
- // Recursive invocation, parsing Holders contained in the
- // previously resolved Holder value.
- propVal = parse(propVal, props, visitedHolders, ignoreBadHolders);
- buf.replace(startIndex, endIndex + DEF_HOLDER_SUFFIX_LEN, propVal);
- startIndex = buf.indexOf(DEF_HOLDER_PREFIX, startIndex + propVal.length());
- } else if (ignoreBadHolders) {
- // Proceed with unprocessed value.
- startIndex = buf.indexOf(DEF_HOLDER_PREFIX, endIndex + DEF_HOLDER_SUFFIX_LEN);
- } else {
- throw new Exception("Could not resolve Placeholder '" + holder + "'");
- }
- visitedHolders.remove(holder);
- } else {
- startIndex = -1;
- }
- }
- return buf.toString();
- }
- private static int findHolderEndIndex(CharSequence buf, int startIndex) {
- int index = startIndex + DEF_HOLDER_PREFIX_LEN;
- int withinNestedHolder = 0;
- while (index < buf.length()) {
- if (StringUtils.substringMatch(buf, index, DEF_HOLDER_SUFFIX)) {
- if (withinNestedHolder > 0) {
- withinNestedHolder--;
- index = index + DEF_HOLDER_SUFFIX_LEN;
- } else {
- return index;
- }
- } else if (StringUtils.substringMatch(buf, index, DEF_HOLDER_PREFIX)) {
- withinNestedHolder++;
- index = index + DEF_HOLDER_PREFIX_LEN;
- } else {
- index++;
- }
- }
- return -1;
- }
- /** *//**
- * Resolve the given Holder using the given properties, performing
- * a system properties check according to the given mode.
- * <p>
- * Default implementation delegates to <code>resolveHolder
- * (Holder, props)</code> before/after the system properties check.
- * <p>
- * Subclasses can override this for custom resolution strategies, including customized points
- * for the system properties check.
- *
- * @param holder
- * the Holder to resolve
- * @param props
- * the merged properties of this configurer
- * @param sysPropsMode
- * the system properties mode,
- * according to the constants in this class
- * @return the resolved value, of null if none
- * @see #setSystemPropertiesMode
- * @see System#getProperty
- * @see #resolveHolder(String, java.util.Properties)
- */
- private static String resolveHolder(String holder, Map<Object, Object> props, int sysPropsMode,
- String defaultValue) {
- String propVal = null;
- if (sysPropsMode == SYS_PROPS_MODE_OVERRIDE) {
- propVal = resolveSystemProperty(holder);
- }
- if (propVal == null) {
- propVal = resolveHolder(holder, props, defaultValue);
- }
- if (propVal == null && sysPropsMode == SYS_PROPS_MODE_FALLBACK) {
- propVal = resolveSystemProperty(holder);
- }
- return propVal;
- }
- /** *//**
- * Resolve the given Holder using the given properties.
- * The default implementation simply checks for a corresponding property key.
- * <p>
- * Subclasses can override this for customized Holder-to-key mappings or custom resolution
- * strategies, possibly just using the given properties as fallback.
- * <p>
- * Note that system properties will still be checked before respectively after this method is
- * invoked, according to the system properties mode.
- *
- * @param holder
- * the Holder to resolve
- * @param props
- * the merged properties of this configurer
- * @return the resolved value, of <code>null</code> if none
- * @see #setSystemPropertiesMode
- */
- private static String resolveHolder(String holder, Map<Object, Object> props,
- String defaultValue) {
- if (props != null) {
- Object value = props.get(holder);
- if (value != null) {
- return "" + value;
- } else if (defaultValue != null) {
- return defaultValue;
- }
- }
- return defaultValue;
- }
- /** *//**
- * Resolve the given key as JVM system property, and optionally also as
- * system environment variable if no matching system property has been found.
- *
- * @param key
- * the Holder to resolve as system property key
- * @return the system property value, or <code>null</code> if not found
- * @see #setSearchSystemEnvironment
- * @see java.lang.System#getProperty(String)
- * @see java.lang.System#getenv(String)
- */
- private static String resolveSystemProperty(String key) {
- try {
- String value = System.getProperty(key);
- if (value == null) {
- value = System.getenv(key);
- }
- return value;
- } catch (Throwable ex) {
- ex.printStackTrace();
- return null;
- }
- }
- }
下面是测试类:
- import java.util.Properties;
- public class PlaceholderStringTest {
- public static void main(String[] args) throws Exception {
- Properties props = new Properties();
- // 在.properties文件中放置key1、key2
- props.put("key1", "Hello");
- props.put("key2", "World");
- String str = null;
- // 替换key1、key2
- str = PlaceholderUtils.parse("Property:${key1}=${key2}", props);
- System.out.println(str);// Property:Hello=World
- // 此处要替换的是 key${index:3},先去看.properties属性中是否有index属性,有则替换其值
- // 再去看系统属性中是否有index属性,有则替换其值
- // 由于都没有index属性,所以取值为 3,也就是要替换 xxx${key3:yyy}
- // 由于key3在.properties文件的属性中、系统属性中均没有此属性,所以返回默认值 yyy
- str = PlaceholderUtils.parse("xxx${key${index:3}:yyy}", props);
- System.out.println(str); // xxxyyy
- // 在.properties文件属性中加入index=2
- props.put("index", "2");
- // 此处的index属性值为2,则替换key2的属性值,默认值yyy被忽略了
- str = PlaceholderUtils.parse("xxx${key${index:3}:yyy}", props);
- System.out.println(str); // xxxWorld
- // 系统属性中加入var1
- System.setProperty("var1", "IamSystem");
- str = PlaceholderUtils.parse("xxx${var1}");
- System.out.println(str); // xxxIamSystem
- System.setProperty("var2", "System2");
- str = PlaceholderUtils.parse("xxx${var1}.${var2}");
- System.out.println(str);// xxxIamSystem.System2
- str = PlaceholderUtils.parse("xxx${var1}.${var3}", true);
- System.out.println(str); // xxxIamSystem.${var3}
- props.clear();
- // 模板
- String dburlTmp = "jdbc:oracle:thin:@${host}:${port:1521}:${service_name}";
- Properties dbProps = new Properties();
- dbProps.put("host", "localhost");
- dbProps.put("service_name", "root");
- str = PlaceholderUtils.parse(dburlTmp, dbProps);
- System.out.println(str); // jdbc:oracle:thin:@localhost:1521:root
- }
- }
通过上面的代码,我们便可以实现自己的placeholder了。再加上Json Schema的校验类,给自己的参数定义Schema,使用时校验配置参数的正确性,然后再进行Placeholder,最后将这些参数生成Json对象,供程序使用,非常方便。
本文地址 : //www.5vq5o.cn/plus/view-191031-1.html
标签: Spring |