spring使用PropertyPlaceholderConfigurer扩展来满足不同环境的参数配置
spring使用PropertyPlaceholderConfigurer扩展来满足不同环境的参数配置,
来自:http://www.javaarch.net/jiagoushi/548.htm
PropertyPlaceholderConfigurer是spring提供我们来把一些环境变量(数据库连接相关参数,文件路径等)统一管理起来,然后在bean中指定对应的变量的。但是往往开发环境,测试环境,生成环境的这些参数配置是不同的,那么我们如何使用PropertyPlaceholderConfigurer扩展来满足不同环境的配置需求,而不需要在不同环境需要修改代码或者配置。
1.我们扩展下PropertyPlaceholderConfigurer,可以通过在properties中production.mode默认配置来或者不同环境的配置,然后有限通过取系统环境变量的这个值来作为我们开发环境,测试环境,生产环境的选择。
import java.io.IOException; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; /** * 可以按照不同的运行模式启用相应的配置 * */ public class MutilPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements InitializingBean { private static final String PRODUCTION_MODE = "production.mode"; // 缓存所有的属性配置 private Properties properties; /** * @return the mode */ public String getMode() { return properties.getProperty(PRODUCTION_MODE); } @Override protected Properties mergeProperties() throws IOException { Properties mergeProperties = super.mergeProperties(); // 根据路由原则,提取最终生效的properties this.properties = new Properties(); // 获取路由规则,系统属性设置mode优先 String mode = System.getProperty(PRODUCTION_MODE); if (StringUtils.isEmpty(mode)) { String str = mergeProperties.getProperty(PRODUCTION_MODE); mode = str != null ? str : "ONLINE"; } properties.put(PRODUCTION_MODE, mode); String[] modes = mode.split(","); Set<Entry<Object, Object>> es = mergeProperties.entrySet(); for (Entry<Object, Object> entry : es) { String key = (String) entry.getKey(); int idx = key.lastIndexOf('_'); String realKey = idx == -1 ? key : key.substring(0, idx); if (!properties.containsKey(realKey)) { Object value = null; for (String md : modes) { value = mergeProperties.get(realKey + "_" + md); if (value != null) { properties.put(realKey, value); break; } } if (value == null) { value = mergeProperties.get(realKey); if (value != null) { properties.put(realKey, value); } else { throw new RuntimeException("impossible empty property for " + realKey); } } } } return properties; } /** * 开放此方法给需要的业务 * * @param key * @return */ public String getProperty(String key) { return resolvePlaceholder(key, properties); } @Override public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub } }
然后我们在properties中可以这么配置:也就是默认配置是ONLINE 生产模式,那么只要在系统变量中没有配置production.mode,则我们取ONLINE的配置,也就是下面的参数取后缀为_ONLINE的配置。
production.mode=ONLINE #lucene index data dir lucene.index.dir_DEV=e:\\logs\\lucene lucene.index.dir_ONLINE=/home/admin/data #velocity file.resource.loader.cache_DEV=false file.resource.loader.modificationCheckInterval_DEV=2 file.resource.loader.cache_ONLINE=true file.resource.loader.modificationCheckInterval_ONLINE=-1对应spring的配置为:
<!-- velocity --> <import resource="classpath*:*.xml" /> <bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="resourceLoaderPath"> <value>WEB-INF/velocity/</value> </property> <property name="velocityProperties"> <props> <prop key="directive.foreach.counter.name">velocityCount</prop> <prop key="directive.foreach.counter.initial.value">1</prop> <prop key="input.encoding">GBK</prop> <prop key="output.encoding">GBK</prop> <prop key="file.resource.loader.cache">${file.resource.loader.cache}</prop> <prop key="file.resource.loader.modificationCheckInterval">${file.resource.loader.modificationCheckInterval}</prop> <prop key="velocimacro.library.autoreload">false</prop> <prop key="velocimacro.library">macro.vm</prop> </props> </property> </bean>
这种参数包括数据库连接串,文件路径等都可以这么配,因为velocity在测试环境不需要cache,能够修改即生效,但是线上环境加上cache则能提高性能,所以,默认使用ONLINE的配置,但是在测试环境的VM参数中加上-Dproduction.mode=DEV,则在开发环境用的是_DEV后缀的配置,到了线上代码则不用改。非常方便。
最好就是架上placeholder的自定义配置bean
<bean id="placeholder" class="org.springweb.core.MutilPropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc.properties</value> <value>classpath*:*-placeholder.properties</value> </list> </property> </bean>