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

既然Spring已經支持了,還研究這個干嘛?

有些要求更高的場景,比如配置放在redis緩存里,或數據庫里,或者存儲在zookeeper節點上,或者屬性的值必須加密存儲,這些spring默認的實現是不夠的,明白上面的原理后,只要把loadProperty()方法的實現按需要修改即可。

 

注:如果把遠程屬性文件加載回來以后,還要做些后續處理,比如解密處理,RemoteProperties類的isSingleton()方法記得要返回false,否則之前的屬性值會因為單例模式而緩存,始終返回的是解密前的原始值。

 

更進一步探討:如果在遠程服務器,寫一個小程序監聽配置文件變化,然后結合ZooKeeper的訂閱、通知機制,子應用監聽到配置變化時,調用ApplicationContext.refresh()方法,刷新上下文環境,理論上講,應用連重啟都不需要。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM