time 
设为首页】【收藏本站
当前位置: 主页 > JAVA > Spring > 顺手牵 Spring中的PropertyPlaceholderConfigurer.java

顺手牵 Spring中的PropertyPlaceholderConfigurer.java

时间:2010-10-17 20:50 点击:4909次 字体:[ ]




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

顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com    <bean id="propertyConfigurer"
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com        class
="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com        
<property name="locations">
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com            
<list>      
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com                
<value>classpath:jdbc.properties</value>
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com            
</list>      
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com        
</property>      
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com    
</bean> 
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com    
<bean id="proxoolDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com        
<property name="driverClassName" value="${driver}" />
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com        
<property name="url" value="${dburl}" />
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com        
<property name="username" value="${username}" /> 
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com        
<property name="password" value="${password}" />
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.com    
</bean>

jdbc.properties:
 

顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.comdriver=oracle.jdbc.OracleDriver
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.comdburl=jdbc:oracle:thin:@localhost:1521:root
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.comusername=myusername
顺手牵 Spring中的PropertyPlaceholderConfigurer.java_www.fengfly.compassword=mypassword


相信上面的配置大家都用到过,
如此配置后 xml 文件中的 "${***}"占位符会被替换成jdbc.properties中对应的属性值。

现在我有一个需求,要求在DB中配置一些参数,如数据库的用户名、密码等,我在参数中提供一个模板,
形如 jdbc:oracle:thin:@${host}:${port:1521}:${service_name}。
然后host、port、service_name从参数表中取得,然后进行替换。
于是,我想到了Spring为我们提供的PropertyPlaceholderConfigurer.java,在看了代码之后,将字符串替换的代码摘出来,为我的需求服务。
下面是我摘出来的字符串解析替换的辅助类:
 

  1. import java.util.HashSet;  
  2. import java.util.Map;  
  3. import java.util.Set;  
  4.  
  5. import org.springframework.util.StringUtils;  
  6.  
  7. public class PlaceholderUtils {  
  8.  
  9.     /** *//** Default Holder prefix: "${" */ 
  10.     public static final String DEF_HOLDER_PREFIX            = "${";  
  11.  
  12.     public static final int    DEF_HOLDER_PREFIX_LEN        = 2;  
  13.  
  14.     /** *//** Default Holder suffix: "}" */ 
  15.     public static final String DEF_HOLDER_SUFFIX            = "}";  
  16.  
  17.     public static final int    DEF_HOLDER_SUFFIX_LEN        = 1;  
  18.     /** *//** Never check system properties. */ 
  19.     public static final int    SYSTEM_PROPERTIES_MODE_NEVER = 0;  
  20.  
  21.     /** *//**  
  22.      * Check system properties if not resolvable in the specified properties.  
  23.      * This is the default.  
  24.      */ 
  25.     public static final int    SYS_PROPS_MODE_FALLBACK      = 1;  
  26.  
  27.     /** *//**  
  28.      * Check system properties first, before trying the specified properties.  
  29.      * This allows system properties to override any other property source.  
  30.      */ 
  31.     public static final int    SYS_PROPS_MODE_OVERRIDE      = 2;  
  32.  
  33.     /** *//**  
  34.      * Parse the given String value recursively, to be able to resolve  
  35.      * nested Holders (when resolved property values in turn contain  
  36.      * Holders again).  
  37.      *   
  38.      * @param strVal  
  39.      *            the String value to parse  
  40.      * @param props  
  41.      *            the Properties to resolve Holders against  
  42.      * @param visitedHolders  
  43.      *            the Holders that have already been visited  
  44.      *            during the current resolution attempt (used to detect circular references  
  45.      *            between Holders). Only non-null if we're parsing a nested Holder.  
  46.      * @throws Exception  
  47.      * @throws AppException  
  48.      *             if invalid values are encountered  
  49.      * @see #resolveHolder(String, java.util.Properties, int)  
  50.      */ 
  51.     public static String parse(String strVal) throws Exception {  
  52.         Set<String> visitedHolders = new HashSet<String>();  
  53.         return parse(strVal, null, visitedHolders, false);  
  54.     }  
  55.  
  56.     public static String parse(String strVal, Map<Object, Object> props) throws Exception {  
  57.         Set<String> visitedHolders = new HashSet<String>();  
  58.         return parse(strVal, props, visitedHolders, false);  
  59.     }  
  60.  
  61.     public static String parse(String strVal, boolean ignoreBadHolders) throws Exception {  
  62.         Set<String> visitedHolders = new HashSet<String>();  
  63.         return parse(strVal, null, visitedHolders, ignoreBadHolders);  
  64.     }  
  65.  
  66.     private static String parse(String strVal, Map<Object, Object> props,  
  67.         Set<String> visitedHolders, boolean ignoreBadHolders) throws Exception {  
  68.  
  69.         StringBuffer buf = new StringBuffer(strVal);  
  70.         int startIndex = strVal.indexOf(DEF_HOLDER_PREFIX);  
  71.         while (startIndex != -1) {  
  72.             int endIndex = findHolderEndIndex(buf, startIndex);  
  73.             if (endIndex != -1) {  
  74.                 String holder = buf.substring(startIndex + DEF_HOLDER_PREFIX_LEN, endIndex);  
  75.                 String defValue = null;  
  76.                 int defIndex = org.apache.commons.lang.StringUtils.lastIndexOf(holder, ":");  
  77.                 if (defIndex >= 0) {  
  78.                     defValue = StringUtils.trimWhitespace(holder.substring(defIndex + 1));  
  79.                     holder = StringUtils.trimWhitespace(holder.substring(0, defIndex));  
  80.                 }  
  81.  
  82.                 if (!visitedHolders.add(holder)) {  
  83.                     throw new Exception("Circular PlaceHolder reference '" + holder  
  84.                         + "' in property definitions");  
  85.                 }  
  86.                 // Recursive invocation, parsing Holders contained in the Holder key.  
  87.                 holder = parse(holder, props, visitedHolders, ignoreBadHolders);  
  88.                 // Now obtain the value for the fully resolved key  
  89.                 String propVal = resolveHolder(holder, props, SYS_PROPS_MODE_FALLBACK, defValue);  
  90.                 if (propVal != null) {  
  91.                     // Recursive invocation, parsing Holders contained in the  
  92.                     // previously resolved Holder value.  
  93.                     propVal = parse(propVal, props, visitedHolders, ignoreBadHolders);  
  94.                     buf.replace(startIndex, endIndex + DEF_HOLDER_SUFFIX_LEN, propVal);  
  95.                     startIndex = buf.indexOf(DEF_HOLDER_PREFIX, startIndex + propVal.length());  
  96.                 } else if (ignoreBadHolders) {  
  97.                     // Proceed with unprocessed value.  
  98.                     startIndex = buf.indexOf(DEF_HOLDER_PREFIX, endIndex + DEF_HOLDER_SUFFIX_LEN);  
  99.                 } else {  
  100.                     throw new Exception("Could not resolve Placeholder '" + holder + "'");  
  101.                 }  
  102.                 visitedHolders.remove(holder);  
  103.             } else {  
  104.                 startIndex = -1;  
  105.             }  
  106.         }  
  107.  
  108.         return buf.toString();  
  109.     }  
  110.  
  111.     private static int findHolderEndIndex(CharSequence buf, int startIndex) {  
  112.         int index = startIndex + DEF_HOLDER_PREFIX_LEN;  
  113.         int withinNestedHolder = 0;  
  114.         while (index < buf.length()) {  
  115.             if (StringUtils.substringMatch(buf, index, DEF_HOLDER_SUFFIX)) {  
  116.                 if (withinNestedHolder > 0) {  
  117.                     withinNestedHolder--;  
  118.                     index = index + DEF_HOLDER_SUFFIX_LEN;  
  119.                 } else {  
  120.                     return index;  
  121.                 }  
  122.             } else if (StringUtils.substringMatch(buf, index, DEF_HOLDER_PREFIX)) {  
  123.                 withinNestedHolder++;  
  124.                 index = index + DEF_HOLDER_PREFIX_LEN;  
  125.             } else {  
  126.                 index++;  
  127.             }  
  128.         }  
  129.         return -1;  
  130.     }  
  131.  
  132.     /** *//**  
  133.      * Resolve the given Holder using the given properties, performing  
  134.      * a system properties check according to the given mode.  
  135.      * <p>  
  136.      * Default implementation delegates to <code>resolveHolder  
  137.      * (Holder, props)</code> before/after the system properties check.  
  138.      * <p>  
  139.      * Subclasses can override this for custom resolution strategies, including customized points  
  140.      * for the system properties check.  
  141.      *   
  142.      * @param holder  
  143.      *            the Holder to resolve  
  144.      * @param props  
  145.      *            the merged properties of this configurer  
  146.      * @param sysPropsMode  
  147.      *            the system properties mode,  
  148.      *            according to the constants in this class  
  149.      * @return the resolved value, of null if none  
  150.      * @see #setSystemPropertiesMode  
  151.      * @see System#getProperty  
  152.      * @see #resolveHolder(String, java.util.Properties)  
  153.      */ 
  154.     private static String resolveHolder(String holder, Map<Object, Object> props, int sysPropsMode,  
  155.         String defaultValue) {  
  156.         String propVal = null;  
  157.         if (sysPropsMode == SYS_PROPS_MODE_OVERRIDE) {  
  158.             propVal = resolveSystemProperty(holder);  
  159.         }  
  160.         if (propVal == null) {  
  161.             propVal = resolveHolder(holder, props, defaultValue);  
  162.         }  
  163.         if (propVal == null && sysPropsMode == SYS_PROPS_MODE_FALLBACK) {  
  164.             propVal = resolveSystemProperty(holder);  
  165.         }  
  166.         return propVal;  
  167.     }  
  168.  
  169.     /** *//**  
  170.      * Resolve the given Holder using the given properties.  
  171.      * The default implementation simply checks for a corresponding property key.  
  172.      * <p>  
  173.      * Subclasses can override this for customized Holder-to-key mappings or custom resolution  
  174.      * strategies, possibly just using the given properties as fallback.  
  175.      * <p>  
  176.      * Note that system properties will still be checked before respectively after this method is  
  177.      * invoked, according to the system properties mode.  
  178.      *   
  179.      * @param holder  
  180.      *            the Holder to resolve  
  181.      * @param props  
  182.      *            the merged properties of this configurer  
  183.      * @return the resolved value, of <code>null</code> if none  
  184.      * @see #setSystemPropertiesMode  
  185.      */ 
  186.     private static String resolveHolder(String holder, Map<Object, Object> props,  
  187.         String defaultValue) {  
  188.         if (props != null) {  
  189.             Object value = props.get(holder);  
  190.             if (value != null) {  
  191.                 return "" + value;  
  192.             } else if (defaultValue != null) {  
  193.                 return defaultValue;  
  194.             }  
  195.         }  
  196.  
  197.         return defaultValue;  
  198.     }  
  199.  
  200.     /** *//**  
  201.      * Resolve the given key as JVM system property, and optionally also as  
  202.      * system environment variable if no matching system property has been found.  
  203.      *   
  204.      * @param key  
  205.      *            the Holder to resolve as system property key  
  206.      * @return the system property value, or <code>null</code> if not found  
  207.      * @see #setSearchSystemEnvironment  
  208.      * @see java.lang.System#getProperty(String)  
  209.      * @see java.lang.System#getenv(String)  
  210.      */ 
  211.     private static String resolveSystemProperty(String key) {  
  212.         try {  
  213.             String value = System.getProperty(key);  
  214.             if (value == null) {  
  215.                 value = System.getenv(key);  
  216.             }  
  217.             return value;  
  218.         } catch (Throwable ex) {  
  219.             ex.printStackTrace();  
  220.             return null;  
  221.         }  
  222.     }  


下面是测试类:
 


 

  1. import java.util.Properties;  
  2.  
  3. public class PlaceholderStringTest {  
  4.     public static void main(String[] args) throws Exception {  
  5.         Properties props = new Properties();  
  6.         // 在.properties文件中放置key1、key2  
  7.         props.put("key1""Hello");  
  8.         props.put("key2""World");  
  9.           
  10.         String str = null;  
  11.         // 替换key1、key2  
  12.         str = PlaceholderUtils.parse("Property:${key1}=${key2}", props);  
  13.         System.out.println(str);// Property:Hello=World  
  14.  
  15.         // 此处要替换的是 key${index:3},先去看.properties属性中是否有index属性,有则替换其值  
  16.         // 再去看系统属性中是否有index属性,有则替换其值  
  17.         // 由于都没有index属性,所以取值为 3,也就是要替换 xxx${key3:yyy}  
  18.         // 由于key3在.properties文件的属性中、系统属性中均没有此属性,所以返回默认值 yyy  
  19.         str = PlaceholderUtils.parse("xxx${key${index:3}:yyy}", props);  
  20.         System.out.println(str); // xxxyyy  
  21.  
  22.         // 在.properties文件属性中加入index=2  
  23.         props.put("index""2");  
  24.  
  25.         // 此处的index属性值为2,则替换key2的属性值,默认值yyy被忽略了  
  26.         str = PlaceholderUtils.parse("xxx${key${index:3}:yyy}", props);  
  27.         System.out.println(str); // xxxWorld  
  28.  
  29.         // 系统属性中加入var1  
  30.         System.setProperty("var1""IamSystem");  
  31.         str = PlaceholderUtils.parse("xxx${var1}");  
  32.         System.out.println(str); // xxxIamSystem  
  33.  
  34.         System.setProperty("var2""System2");  
  35.         str = PlaceholderUtils.parse("xxx${var1}.${var2}");  
  36.         System.out.println(str);// xxxIamSystem.System2  
  37.  
  38.         str = PlaceholderUtils.parse("xxx${var1}.${var3}"true);  
  39.         System.out.println(str); // xxxIamSystem.${var3}   
  40.         props.clear();  
  41.           
  42.         // 模板  
  43.         String dburlTmp = "jdbc:oracle:thin:@${host}:${port:1521}:${service_name}";  
  44.         Properties dbProps = new Properties();  
  45.         dbProps.put("host""localhost");  
  46.         dbProps.put("service_name""root");  
  47.         str = PlaceholderUtils.parse(dburlTmp, dbProps);  
  48.         System.out.println(str); // jdbc:oracle:thin:@localhost:1521:root  
  49.     }  

通过上面的代码,我们便可以实现自己的placeholder了。再加上Json Schema的校验类,给自己的参数定义Schema,使用时校验配置参数的正确性,然后再进行Placeholder,最后将这些参数生成Json对象,供程序使用,非常方便。
 



本文地址 : http://www.fengfly.com/plus/view-191031-1.html
标签: Spring
------分隔线----------------------------
最新评论 查看所有评论
发表评论 查看所有评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
验证码: