为了账号安全,请及时绑定邮箱和手机立即绑定

spring: 加载远程配置

标签:
SpringBoot

通常在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:\test\resources\application.properties" />
 11     </bean>

复制代码

既然Spring已经支持了,还研究这个干嘛?

有些要求更高的场景,比如配置放在redis缓存里,或数据库里,或者存储在zookeeper节点上,或者属性的值必须加密存储,这些spring默认的实现是不够的,明白上面的原理后,只要把loadProperty()方法的实现按需要修改即可。

 

注:如果把远程属性文件加载回来以后,还要做些后续处理,比如解密处理,RemoteProperties类的isSingleton()方法记得要返回false,否则之前的属性值会因为单例模式而缓存,始终返回的是解密前的原始值。

 

更进一步探讨:如果在远程服务器,写一个小程序监听配置文件变化,然后结合ZooKeeper的订阅、通知机制,子应用监听到配置变化时,调用ApplicationContext.refresh()方法,刷新上下文环境,理论上讲,应用连重启都不需要。

  

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消