目录

配置中心的实现

服务端

在配置中心服务端统一配置项目配置

界面配置

登陆后,选择环境,选择项目,增删改查配置项和配置值

获取配置

请求地址

http://IP:PORT/config_center/config/queryByEnvAndProject.htm?userName=[name]&password=[password]&env=[环境]&project=[项目]

输出

{
    "message": "根据环境和项目查询配置信息成功!",
    "list": [
        {
            "id": 8,
            "env": "prod",
            "project": "record_app",
            "name": "DAILY_RECORD_IMAGE_DIR",
            "value": "/mnt/lost+found/FILES/RECORD_APP/images/daily/",
            "remark": "日常记录图片文件夹",
            "createDate": "20151225",
            "createTime": "161751",
            "updateDate": "20151225",
            "updateTime": "162225"
        },
        {
            "id": 9,
            "env": "prod",
            "project": "record_app",
            "name": "DAILY_RECORD_IMAGE_URL_PREFIX",
            "value": "http://cdn.recorddrip.com/RECORD_APP/images/daily/",
            "remark": "日常记录图片URL前缀",
            "createDate": "20151225",
            "createTime": "162257",
            "updateDate": "20170108",
            "updateTime": "162450"
        },
        {
            "id": 10,
            "env": "prod",
            "project": "record_app",
            "name": "DEFAULT_HEAD_PHOTO_URL",
            "value": "http://cdn.recorddrip.com/RECORD_APP/images/head/default/default_20151101.png",
            "remark": "默认头像URL",
            "createDate": "20151225",
            "createTime": "162659",
            "updateDate": "20170108",
            "updateTime": "162500"
        },
        {
            "id": 15,
            "env": "prod",
            "project": "record_app",
            "name": "redis.host",
            "value": "121.43.104.34",
            "remark": "redis服务IP地址",
            "createDate": "20151225",
            "createTime": "165240",
            "updateDate": "20161128",
            "updateTime": "192718"
        },
        {
            "id": 16,
            "env": "prod",
            "project": "record_app",
            "name": "redis.port",
            "value": "6379",
            "remark": "redis服务端口",
            "createDate": "20151225",
            "createTime": "165249",
            "updateDate": "20170125",
            "updateTime": "144858"
        },
        {
            "id": 17,
            "env": "prod",
            "project": "record_app",
            "name": "redis.pass",
            "value": "******",
            "remark": "redis服务密码",
            "createDate": "20151225",
            "createTime": "165300",
            "updateDate": "20151225",
            "updateTime": "165300"
        },
        ...
    ],
    "isSuccess": true
}

客户端

具体项目里的配置,从服务端获取,参考上面的[获取配置],具体实现如下

占位符使用

spring配置文件中的占位符,还是按正常写${配置键}

application-cache-redis.xml
...
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
        p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"  p:pool-config-ref="poolConfig"/>
...

传统的属性文件

配置类似xxx.properties后,占位符${配置键},会从该属性文件中寻找配置的值。

application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/security 
		http://www.springframework.org/schema/security/spring-security-3.2.xsd
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/data/jpa 
		http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
	<!-- 属性配置文件 -->
	<context:property-placeholder location="classpath:xxx.properties" />
 
</beans>

自定义属性占位符配置子类

application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/security 
		http://www.springframework.org/schema/security/spring-security-3.2.xsd
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/data/jpa 
		http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
	<!-- Activates annotation-based bean configuration -->
	<context:annotation-config />
 
	<!-- Scans for application @Components to deploy -->
	<context:component-scan base-package="com.gxx.record_app" />
 
	<!-- 自建属性文件读取子类BEAN 构造方法读取配置中心 -->
	<bean class="com.gxx.record_app.config.MinePropertyPlaceholderConfigurer" />
 
</beans>
MinePropertyPlaceholderConfigurer.java
package com.gxx.record_app.config;
 
import java.io.File;
import java.util.Properties;
import java.util.Set;
 
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
 
import com.gxx.record_app.utils.HttpClientUtils;
import com.gxx.record_app.utils.PropertyUtil;
 
/**
 * 
 * <dl>
 *    <dt><b>Title:</b></dt>
 *    <dd>
 *    	none
 *    </dd>
 *    <dt><b>Description:自建属性文件读取子类BEAN 构造方法读取配置中心</b></dt>
 *    <dd>
 *    	<p>none
 *    </dd>
 * </dl>
 *
 * @author Gxx
 * @version 1.0, 2015年12月30日
 * @since record_app
 *
 */
public class MinePropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
 
	/**
	 * 日志处理器
	 */
	private final Logger logger = Logger.getLogger(MinePropertyPlaceholderConfigurer.class);
 
	/**
	 * 本地配置文件位置
	 */
	private static final String CONFIG_FILE_LOCATION = "CONFIG_FILE_LOCATION";
 
	/**
	 * 配置中心地址
	 */
	private static final String CONFIG_CENTER_URL = "config.center.url";
 
	/**
	 * 构造方法
	 */
	public MinePropertyPlaceholderConfigurer(){
		/**
		 * 读取配置
		 */
		readConfig();
	}
 
	/**
	 * 读取配置
	 */
	public void readConfig(){
		try{
			/**
			 * 1.读取配置文件位置
			 */
			String configFileLocation = PropertyUtil.getInstance().getProperty(CONFIG_FILE_LOCATION);
			String configFile = StringUtils.EMPTY;
			for(String location : configFileLocation.split(",")){
				File file = new File(location);
				if(file.exists()){
					configFile = location;
					break;
				}
			}
			logger.info("本地配置文件路径:" + configFile);
			/**
			 * 2.找不到配置文件报错
			 */
			if(StringUtils.isBlank(configFile)){
				throw new RuntimeException("该环境不存在配置文件");
			}
			/**
			 * 3.载入本地环境中的配置文件
			 */
			logger.info("载入本地环境中的配置文件");
			PropertyUtil.getInstance().refreshRealPath(configFile);
			/**
			 * 4.读取配置中心地址
			 */
			String configCenterUrl = PropertyUtil.getInstance().getProperty(CONFIG_CENTER_URL);
			logger.info("读取配置中心地址:" + configCenterUrl);
			/**
			 * 5.从配置中心读取配置
			 */
			String content = HttpClientUtils.getWebContentByGet(configCenterUrl);
	    	logger.info("从配置中心读取配置,返回内容:" + content);
	    	/**
	    	 * 6.json解析
	    	 */
	    	JSONObject jsonObject = new JSONObject(content);
	    	logger.info("contentMap:isSuccess=" + (jsonObject.getBoolean("isSuccess")?"Y":"N")
	    			+ ",message=" + jsonObject.getString("message"));
	    	/**
	    	 * 7.判断是否读取配置成功
	    	 */
	    	logger.info("判断是否读取配置成功:[" + (jsonObject.getBoolean("isSuccess")?"成功":"失败") + "]");
	    	if(!jsonObject.getBoolean("isSuccess")){
	    		throw new RuntimeException("读取配置中心配置失败!");
	    	}
	    	/**
	    	 * 8.将配置中心读取的配置塞入本地Properties,如果本地配置文件有该配置则以本地优先级高,再把本地Properties塞入System properties
	    	 */
	    	logger.info("将配置中心读取的配置塞入本地Properties,如果本地配置文件有该配置则以本地优先级高,再把本地Properties塞入System properties。");
	    	JSONArray jsonArray = new JSONArray(jsonObject.getString("list"));
	        for(int index = 0, length = jsonArray.length(); index < length; index++) {
	        	JSONObject tempObject = jsonArray.getJSONObject(index);
	        	logger.info("id=" + tempObject.getLong("id")
	    				+ ",env=" + tempObject.getString("env")
	    				+ ",project=" + tempObject.getString("project")
	    				+ ",name=" + tempObject.getString("name")
	    				+ ",value=" + tempObject.getString("value")
	    				+ ",remark=" + tempObject.getString("remark"));
	        	String name = tempObject.getString("name");
	        	String localValue = PropertyUtil.getInstance().getProperty(name);
	        	if(localValue == null){
	        		localValue = tempObject.getString("value");
	        		PropertyUtil.getInstance().setProperty(name, localValue);
	        	} else {
	        		logger.info("本地已经配置,优先级较高:" + tempObject.getString("name") + "=" + localValue);
	        	}
	        }
	        Properties properties = PropertyUtil.getInstance().getProperties();
	        Set<Object> set = properties.keySet();
	        for(Object key : set){
	        	String value = properties.getProperty((String)key);
	        	System.setProperty((String)key, value);
	        	logger.info("设置System Property[" + key + "]=[" + value + "]");
	        }
		} catch (Exception ex){
			logger.error("异常发生!", ex);
		}
	}
}