spring: 加载远程配置
通常在spring应用中,配置中的properties文件,都是打包在war包里的,部署规模较小,只有几台服务器时,这样并没有什么大问题。如果服务器多了,特别是集群部署时,如果要修改某一项配置,得重新打包、部署,一台台机器改过去,十分麻烦。
看了Spring-Cloud项目,深受启发,Spring-Cloud把配置文件放在远程的git或svn这类云平台之上,所有应用启动时从云上获取配置,配置需要修改时,直接修改git上的配置即可,十分方便,但是这个项目并不简单,新概念太多,需要一定时间熟悉。
借鉴一下spring-cloud的理念,我们可以把properties文件放在局域网的网络位置上,启动时远程加载即可,核心实现类:
package org.demo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.StringUtils;
import java.util.Properties;
/**
* load remote properties
*/
public class RemoteProperties implements InitializingBean, FactoryBean<Properties> {
Logger logger = LogManager.getLogger();
private String url = null;
private Properties properties = new Properties();
@Override
public Properties getObject() throws Exception {
return properties;
}
@Override
public Class<?> getObjectType() {
return properties.getClass();
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void afterPropertiesSet() throws Exception {
loadProperty();
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
private void loadProperty() {
if (StringUtils.isEmpty(url)) return;
logger.debug("loading remote properties:" + url);
String content = HttpUtil.get(url);
logger.debug("remote properties conent:" + content);
String[] lines = content.replaceAll("r", "").split("n");
for (String line : lines) {
if (!StringUtils.isEmpty(line)) {
String[] arr = line.split("=");
properties.put(arr[0].trim(), arr[1].trim());
}
}
}
}
代码不复杂,增加了一个url属性,用来获取远程属性文件的位置,然后在loadProperty里,发起http的get请求,把属性文件的内容拿回来,存储到本地properties变量中。使用时,配置里这么写:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:p="http://www.springframework.org/schema/p"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
6
7 <bean id="propertyPlaceholderConfigurer"
8 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
9
10 <!-- during developing, you can uncomment this to load local properties -->
11 <!-- <property name="location" value="application.properties"/> -->
12
13 <property name="properties">
14 <bean id="remoteProperties" class="org.demo.RemoteProperties"
15 p:url="http://172.21.12*.**/config/dev/application.properties"/>
16 </property>
17 </bean>
18
19 <bean class="org.demo.Foo" p:name="${name}"></bean>
20
21 </beans>
注意13-16行,这里指定远程属性的位置,在开发阶段,为了方便调试,可以把上面注释的部分去掉,这样相当于直接使用本地properties文件。
我在淘宝Code,上传了一个示例程序spring-load-remote-config,方便大家参考。
当然,其实从文件路径或http网址远程属性文件,Spring本身就支持的,配置示例如下:
1 <bean id="propertiesFactoryBean1"
2 class="org.springframework.beans.factory.config.PropertiesFactoryBean">
3 <property name="location"
4 value="http://172.21.*.*/config/dev/application.properties" />
5 </bean>
6
7 <bean id="propertiesFactoryBean2"
8 class="org.springframework.beans.factory.config.PropertiesFactoryBean">
9 <property name="location"
10 value="file:D:testresourcesapplication.properties" />
11 </bean>
既然Spring已经支持了,还研究这个干嘛?
有些要求更高的场景,比如配置放在redis缓存里,或数据库里,或者存储在zookeeper节点上,或者属性的值必须加密存储,这些spring默认的实现是不够的,明白上面的原理后,只要把loadProperty()方法的实现按需要修改即可。
注:如果把远程属性文件加载回来以后,还要做些后续处理,比如解密处理,RemoteProperties类的isSingleton()方法记得要返回false,否则之前的属性值会因为单例模式而缓存,始终返回的是解密前的原始值。
更进一步探讨:如果在远程服务器,写一个小程序监听配置文件变化,然后结合ZooKeeper的订阅、通知机制,子应用监听到配置变化时,调用ApplicationContext.refresh()方法,刷新上下文环境,理论上讲,应用连重启都不需要。
- Spring JDBCTemplate使用JNDI数据源
- 大家之前是不是误解了DC/OS与Kubernetes之间的关系
- CentOS 7 上部署Mono 4 和Jexus 5.6
- maven学习(下)利用Profile构建不同环境的部署包
- AS3初学者容易迷糊的几个问题
- Spring Security笔记:自定义Login/Logout Filter、AuthenticationProvider、AuthenticationToken
- ASP.NET Web API 2.1支持Binary JSON(Bson)
- Spring Security笔记:自定义登录页
- 浅析 Linux 初始化 init 系统
- 如何提高Python运行效率 超实用的四种提速方法
- 如何让oracle的select强制走索引
- ActionScript3.0(AS3)中的泛型数组Vector
- 人民网评:“算法推荐”不能成为传播低俗信息的助推器
- 代码实现WordPress自动关键词keywords与描述description
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- yum install空间不足
- prometheus-nginxlog-exporter构建Nginx日志监控
- s3cmd put文件的过程
- Ceph RGW配置Nginx代理出现S3Error: 403 (Forbidden)
- OmniDiskSweeper清理系统文件
- 【Kubernetes】通过ConfigMap修改容器的DNS
- 【Tensorflow 2.x】检验MKL
- kubernetes dashboard insecure配置
- seqtk抽取reads
- Version of Delve is too old for this version of Go【Goland Debug】报错
- python之turtle模块-黄金螺线
- python之turtle模块-生化危机
- Python之turtle模块-饼状图
- python之turtle模块-弧线
- Python之turtle模块-画圈圈