继承PropertyPlaceholderConfigurer实现自定义解析占位符策略

  • Post author:
  • Post category:其他


spring提供的PropertyPlaceholderConfigurer都是根据指定的配置文件解析占位符,

在实际生产环境中,更常见的需求是从数据库中加载配置信息,根据加载的配置信息解析占位符。

本文将讨论如何继承PropertyPlaceholderConfigurer,实现自定义解析占位符的策略

继承Spring的PropertyPlaceholderConfigurer,重写方法,实现从数据库加载配置信息,目前就我所了解到的,有2种方法:

1、重写mergeProperties()方法

2、重写resolvePlaceHolder()方法

mergeProperties()方法的介绍-来自

官网API

protected java.util.Properties mergeProperties()  throws java.io.IOException

Return a merged Properties instance containing both the loaded properties and properties set on this FactoryBean.

该方法扩充了获取properties的渠道。

resolvePlaceHolder()方法的介绍

protected java.lang.String resolvePlaceholder(java.lang.String placeholder,

java.util.Properties props)

Resolve the given placeholder using the given properties. The default implementation simply checks for a corresponding property key.

Subclasses can override this for customized placeholder-to-key mappings or custom resolution strategies, possibly just using the given properties as fallback.

Note that system properties will still be checked before respectively after this method is invoked, according to the system properties mode.

Parameters:

placeholder – the placeholder to resolve

props – the merged properties of this configurer

Returns:

the resolved value, of null if none

该方法扩充了解析占位符的方式。重写逻辑一般为,如果在merged properties中没有相应的属性供解析占位符,则使用自定义的从占位符到属性值的映射。

原英文译文为:使用给定的属性解析给定的占位符。 默认实现只是检查相应的属性键。

子类可以覆盖此自定义占位符到键映射或自定义解析策略,可能只是使用给定属性作为后备。

请注意,根据系统属性模式,在调用此方法之后,系统属性仍将分别进行检查。

两种方式大同小异,第一种方法是先将自定义的从占位符到属性值的映射加入merged properties

第二种方法是在解析占位符时,再使用自定义的从占位符到属性值的映射

第一种方法实现转载自以下博文:


重写Spring的PropertyPlaceholderConfigurer,从数据库加载配置数据

1,applicationContext.xml

用自定义扩展类DataBasePropertyPlaceholderConfigurer替换Spring的PropertyPlaceholderConfigurer

<!– 从数据库配置表加载系统配置属性 –>

<bean id=”dataBasePropertyConfigurer” class=”com.crc.util.DataBasePropertyPlaceholderConfigurer”>

</bean>

2,DataBasePropertyPlaceholderConfigurer.java



  1. package


    com.crc.util;




  2. import


    java.util.Properties;



  3. import


    org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;




  4. public




    class


    DataBasePropertyPlaceholderConfigurer


    extends


    PropertyPlaceholderConfigurer


  5. {


  6. @Override





  7. public


    Properties mergeProperties()


  8. {


  9. return


    ConfigPropertiesUtil.getProperties();


  10. }


  11. }

3,ConfigPropertiesUtil.java,从数据库读取配置数据的工具类



  1. package


    com.crc.util;



  2. import


    java.sql.Connection;



  3. import


    java.sql.PreparedStatement;



  4. import


    java.sql.ResultSet;



  5. import


    java.sql.SQLException;



  6. import


    java.util.Properties;



  7. import


    java.util.concurrent.locks.ReentrantReadWriteLock;



  8. import


    javax.naming.Context;



  9. import


    javax.naming.InitialContext;



  10. import


    javax.naming.NamingException;



  11. import


    javax.sql.DataSource;



  12. import


    org.slf4j.Logger;



  13. import


    org.slf4j.LoggerFactory;





  14. public




    class


    ConfigPropertiesUtil


  15. {


  16. private




    static




    final


    String JNDI_PREFIX =


    “java:comp/env/”


    ;



  17. private




    static




    final


    String JNDI_NAME =


    “jdbc/reimburse”


    ;




  18. private




    static


    Properties properties =


    null


    ;




  19. private




    static




    final


    ReentrantReadWriteLock readWriteLock =


    new


    ReentrantReadWriteLock();




  20. private




    static




    final


    String queryString =


    “select t.property_key, t.property_value from appmgr.t_config_properties t”


    ;




  21. private




    static




    final


    Logger logger = LoggerFactory.getLogger(ConfigPropertiesUtil.


    class


    );





  22. private


    ConfigPropertiesUtil() {



  23. }




  24. public




    static


    String getValueByKey(String key)


  25. {


  26. if


    (key ==


    null


    ||


    “”


    .equals(key.trim()))


  27. {


  28. return




    “”


    ;


  29. }


  30. loadProperties();



  31. return


    properties.get(key) ==


    null


    ?


    “”


    : properties.get(key).toString();


  32. }




  33. public




    static


    Properties getProperties()


  34. {

  35. loadProperties();


  36. return


    properties;


  37. }




  38. private




    static




    void


    loadProperties()


  39. {

  40. readWriteLock.readLock().lock();



  41. if


    (properties ==


    null


    )


  42. {

  43. readWriteLock.readLock().unlock();

  44. readWriteLock.writeLock().lock();



  45. if


    (properties ==


    null


    )


  46. {

  47. properties =

    new


    Properties();



  48. DataSource dataSource =

    null


    ;


  49. Connection connection =

    null


    ;


  50. PreparedStatement statement =

    null


    ;


  51. ResultSet resultSet =

    null


    ;



  52. Context context =

    null


    ;



  53. try




  54. {

  55. context =

    new


    InitialContext();


  56. }


  57. catch


    (NamingException e3)


  58. {

  59. logger.error(

    “初始化JNDI上下文出错(加载系统配置数据):”


    , e3);


  60. readWriteLock.writeLock().unlock();


  61. return


    ;


  62. }



  63. try




  64. {

  65. dataSource = (DataSource)(context.lookup(JNDI_NAME));

  66. }


  67. catch


    (NamingException e1)


  68. {


  69. try




  70. {

  71. dataSource = (DataSource)(context.lookup(JNDI_PREFIX + JNDI_NAME));

  72. }


  73. catch


    (NamingException e2)


  74. {

  75. logger.error(

    “获取JNDI数据源出错(加载系统配置数据):”


    , e2);


  76. readWriteLock.writeLock().unlock();


  77. return


    ;


  78. }

  79. }



  80. try




  81. {

  82. connection = dataSource.getConnection();

  83. statement = connection.prepareStatement(queryString);

  84. resultSet = statement.executeQuery();



  85. while


    (resultSet.next())


  86. {

  87. properties.setProperty(resultSet.getString(

    1


    ), resultSet.getString(


    2


    ) ==


    null


    ?


    “”


    : resultSet.getString(


    2


    ).trim());


  88. }


  89. logger.info(

    “==========================加载配置数据开始============================”


    );


  90. logger.info(properties.toString());

  91. logger.info(

    “==========================加载配置数据结束============================”


    );


  92. }


  93. catch


    (Exception e)


  94. {

  95. logger.error(

    “加载系统配置数据出错:”


    , e);


  96. }


  97. finally




  98. {


  99. if


    (resultSet !=


    null


    )


  100. {


  101. try




  102. {

  103. resultSet.close();

  104. }


  105. catch


    (SQLException e)


  106. {

  107. e.printStackTrace();

  108. }

  109. }


  110. if


    (statement !=


    null


    )


  111. {


  112. try




  113. {

  114. statement.close();

  115. }


  116. catch


    (SQLException e)


  117. {

  118. e.printStackTrace();

  119. }

  120. }


  121. if


    (connection !=


    null


    )


  122. {


  123. try




  124. {

  125. connection.close();

  126. }


  127. catch


    (SQLException e)


  128. {

  129. e.printStackTrace();

  130. }

  131. }

  132. }

  133. }


  134. readWriteLock.readLock().lock();

  135. readWriteLock.writeLock().unlock();

  136. }


  137. readWriteLock.readLock().unlock();

  138. }


  139. }

第二种方法实现:

import java.util.ArrayList;
import java.util.List;

/**
 * 
 */

import java.util.Map;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

import com.service.configuration.ConfigListenerSvc;
import com.service.configuration.constants.ConfigurationConstants;
import com.service.configuration.utils.DecryptUtil;
import com.service.configuration.utils.HttpClientConnectionManager;

import lombok.extern.slf4j.Slf4j;

/**
 * @project configuration
 * @description 重写PropertyPlaceholderConfigurer的resolvePlaceholder方法,
 *              当从指定的Properties文件中读取不到配置项时,尝试从配置中心读取所有配置信息。
 * @copyright Copyright (c) 2016 foresee
 * @company foresee
 * @author Tim
 * @version 1.0
 * @history 修订历史(历次修订内容、修订人、修订时间等)
 *
 */
@Slf4j
public class DatabasePropertyPlaceholder extends PropertyPlaceholderConfigurer {
	
	private static Map<String, String> dbPropertyValues = null;

	public DatabasePropertyPlaceholder() {
		String delay = getDbProperty("conf.refresh.delay");
		int de = 60;
		if (delay == null) {
			log.info("配置中心没有设置conf.refresh.delay参数,使用默认值:60。");
		} else {
			de = Integer.parseInt(delay);
		}
		// 每分钟执行一次刷新配置缓存
		Timer timer = new Timer();
		timer.schedule(new MyTask(), de * 1000, de * 1000);
	}

	/**
	 * 从配置中心获取配置项
	 * 
	 * @param placeholder
	 * @return
	 */
	public static String getDbProperty(String placeholder) {
		String value = null;
		if (dbPropertyValues == null) {
			dbPropertyValues = getDbPropertyValuesFromConfCenter();
		}
		if (dbPropertyValues != null) {
			value = dbPropertyValues.get(placeholder);
		}
		return value;
	}

	public static List<String> getDbPropertyLst(String placeholder) {
		List<String> valuelst = new ArrayList<String>();
		if (dbPropertyValues == null) {
			dbPropertyValues = getDbPropertyValuesFromConfCenter();
		}
		if (dbPropertyValues != null) {
			for (Map.Entry<String, String> entry : dbPropertyValues.entrySet()) {
				// dbPropertyValues.set(entry.getKey(), entry.getValue());
				if (entry.getKey().startsWith(placeholder)) {
					valuelst.add(entry.getValue());
				}
			}
			// value = dbPropertyValues.get(placeholder);
		}
		return valuelst;

	}

	@Override
	protected String resolvePlaceholder(String placeholder, Properties props) {
		String value = props.getProperty(placeholder);
		if (value == null) {
			value = getDbProperty (placeholder);
		}
		return value;
	}

	/**
	 * 从配置中心读取配置表
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static Map<String, String> getDbPropertyValuesFromConfCenter() {
		String confCenterAddr = System.getProperty("confCenterAddr");
		if (confCenterAddr == null) {
			confCenterAddr = "http://localhost:6789/confCenter/conf";
		}
		String confTable = System.getProperty("confTable");
		// 请求配置中心获取配置表信息,然后载入dbPropertyValues中
		String url = confCenterAddr + (confTable == null ? "" : "?confTable=" + confTable);
		HttpGet get = HttpClientConnectionManager.getGetMethod(url);
		HttpResponse response = null;
		try {
			log.info("准备请求配置中心获取配置文件,配置表为:"
					+ (confTable == null ? ConfigurationConstants.DEFAULT_CONFIGURATION_TABLENAME : confTable));
			response = HttpClientConnectionManager.createHttpClient().execute(get);
			String jsonStr = EntityUtils.toString(response.getEntity(), "utf-8");
			Map<String, String> values = new ObjectMapper().readValue(jsonStr, Map.class);
			// 开始解密
			log.info("对配置表"+(confTable == null ? ConfigurationConstants.DEFAULT_CONFIGURATION_TABLENAME : confTable)+"进行解密...");
			
			values =DecryptUtil.doDecryptMap(values);
			log.info("读取配置表" + (confTable == null ? ConfigurationConstants.DEFAULT_CONFIGURATION_TABLENAME : confTable)
					+ "成功!");
			return values;
		} catch (Exception e) {
			e.printStackTrace();
			log.debug("请求配置中心获取配置信息失败!", e);
		}
		return null;
	}

	/**
	 * 刷新配置中心缓存
	 * 
	 * @project configuration
	 * @copyright Copyright (c) 2016 foresee
	 * @company foresee
	 * @author Tim
	 * @version 1.0
	 * @history 修订历史(历次修订内容、修订人、修订时间等)
	 */
	class MyTask extends TimerTask {
		public void run() {
			Map<String, String> values = getDbPropertyValuesFromConfCenter();
			if (values != null) {
				dbPropertyValues = values;
			}
			// 执行监听配置中心
			ConfigListenerSvc.getInstance().excute();
		}
	}
}



版权声明:本文为qq_26222859原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。