當項目達到一定程度,配置五花八門這時候配置中心的便派上了用場。
方案1 maven打包
如果只是要區(qū)分開發(fā)環(huán)境和上線環(huán)境的配置,只要打包的時候吧不同文件環(huán)境打包進來就ok了
maven舉例
<profiles>
<profile>
<id>local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<package.environment>local</package.environment>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<package.environment>dev</package.environment>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<package.environment>production</package.environment>
</properties>
</profile>
</profiles>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>test/*</exclude>
<exclude>production/*</exclude>
<exclude>development/*</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources/${profiles.active}</directory>
</resource>
</resources>
</build>
或
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
<webResources>
<resource>
<directory>/config/${package.environment}/properties</directory>
<targetPath>WEB-INF/classes/properties</targetPath>
<filtering>false</filtering>
</resource>
</webResources>
</configuration>
</plugin>
mvn package –P dev
方案2 spring profiles
spring為beans標簽提供了profile功能,以便項目的開發(fā)和生成環(huán)境分離。
參考:https://my.oschina.net/yybear/blog/113755
spring boot 不再贅述http://blog.csdn.net/he90227/article/details/52981747
方案3 Spring Cloud Config Server
maven依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.BUILD-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
服務端
@EnableConfigServer
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilderconfigure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class,args);
}
}
配置文件application.properties
(git)
spring.application.name=config-server
server.port=7001
spring.cloud.config.server.git.uri=https://github.com/www1350/springclouddemo
##搜索目錄
spring.cloud.config.server.git.searchPaths=properties
spring.cloud.config.server.git.username=aaaa
spring.cloud.config.server.git.password=bbb
spring.cloud.config.enabled=true
(svn)
spring.application.name=config-server
server.port=7001
spring.cloud.config.server.svn.uri=svn://IP:port/project/config
spring.cloud.config.server.svn.username=absurd
spring.cloud.config.enabled=true
spring.cloud.config.server.svn.password=fdsaf
feign-consumer-dev.properties
userid=7
username=123
password=123
- /{application}/{profile}[/{label}]
- [/{label}/]{application}-{profile}.yml
- [/{label}/]{application}-{profile}.properties
http://localhost:7001/feign-consumer/dev/master

或
http://localhost:7001/master/feign-consumer-dev.yml

或
http://localhost:7001/master/feign-consumer-dev.properties

客戶端調(diào)用(bootstrap.properties)
spring.application.name=feign-consumer
spring.cloud.config.profile=dev
spring.cloud.config.label=master
spring.cloud.config.uri=http://localhost:7001/
@RestController
@RefreshScope
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Value("${userid}")
private Long userid;
@Value("${username}")
private String username;
@Value("${password}")
private String password;
@RequestMapping(value="/username",method= RequestMethod.GET)
@ResponseBody
public String getUserName(){
return username;
}
@RequestMapping(value="/dev",method= RequestMethod.GET)
@ResponseBody
public String getUser(){
return userService.getUserByParam(userid);
}
@RequestMapping(value="/{id}",method= RequestMethod.GET)
@ResponseBody
public String getUser(@PathVariable("id") Long id){
return userService.getUser(id);
}
}
下面這種寫法也是可以的。
@Autowired
private Environment environment;
另外,他還提供了很多方式來滿足需求。比如,修改了配置后,可以
$curl -X POST http://localhost:7001/refresh
來刷新配置。
$curl -X POST http://localhost:7001/restart
項目地址:https://github.com/www1350/springclouddemo
官方:https://github.com/spring-cloud/spring-cloud-config
方案4 Disconf
- Distributed Configuration Management Platform(分布式配置管理平臺)
- 專注于各種「分布式系統(tǒng)配置管理」的「通用組件」和「通用平臺」, 提供統(tǒng)一的「配置管理服務」。
功能特點 - 支持配置(配置項+配置文件)的分布式化管理
- 配置發(fā)布統(tǒng)一化
- 配置發(fā)布、更新統(tǒng)一化:
- 同一個上線包 無須改動配置 即可在 多個環(huán)境中(RD/QA/PRODUCTION) 上線
- 配置存儲在云端系統(tǒng),用戶統(tǒng)一管理 多個環(huán)境(RD/QA/PRODUCTION)、多個平臺 的所有配置
- 配置更新自動化:用戶在平臺更新配置,使用該配置的系統(tǒng)會自動發(fā)現(xiàn)該情況,并應用新配置。特殊地,如果用戶為此配置定義了回調(diào)函數(shù)類,則此函數(shù)類會被自動調(diào)用。
- 極簡的使用方式(注解式編程 或 XML無代碼侵入模式):我們追求的是極簡的、用戶編程體驗良好的編程方式。目前支持兩種開發(fā)模式:基于XML配置或者基于注解,即可完成復雜的配置分布式化。
- 低侵入性或無侵入性、強兼容性:
- 低侵入性:通過極少的注解式代碼撰寫,即可實現(xiàn)分布式配置。
- 無侵入性:通過XML簡單配置,即可實現(xiàn)分布式配置。
- 強兼容性:為程序添加了分布式配置注解后,開啟Disconf則使用分布式配置;若關閉Disconf則使用本地配置;若開啟Disconf后disconf-web不能正常Work,則Disconf使用本地配置。
- 支持配置項多個項目共享,支持批量處理項目配置。
- 配置監(jiān)控:平臺提供自校驗功能(進一步提高穩(wěn)定性),可以定時校驗應用系統(tǒng)的配置是否正確。
注:配置項是指某個類里的某個Field字段。
官方文檔:http://disconf.readthedocs.io/zh_CN/latest/
disconf-web安裝
安裝依賴軟件
- Mysql(Ver 14.12 Distrib 5.0.45, for unknown-linux-gnu (x86_64) using EditLine wrapper)
- Tomcat(apache-tomcat-7.0.50)
- Nginx(nginx/1.5.3)
- zookeeeper (zookeeper-3.3.0)
- Redis (2.4.5)
項目地址:https://github.com/knightliao/disconf
打開disconf-web文件夾
- jdbc-mysql.properties (數(shù)據(jù)庫配置)
- redis-config.properties (Redis配置,主要用于web登錄使用)
- zoo.properties (Zookeeper配置)
- application.properties (應用配置)
注意,記得執(zhí)行將application-demo.properties復制成application.properties:
cp application-demo.properties application.properties
上線前的初始化工作
初始化數(shù)據(jù)庫:
可以參考 sql/readme.md 來進行數(shù)據(jù)庫的初始化。注意順序執(zhí)行
0-init_table.sql
1-init_data.sql
201512/20151225.sql
20160701/20160701.sql
里面默認有6個用戶(請注意線上環(huán)境刪除這些用戶以避免潛在的安全問題)
| name | pwd |
|---|---|
| admin | admin |
| testUser1 | MhxzKhl9209 |
| testUser2 | MhxzKhl167 |
| testUser3 | MhxzKhl783 |
| testUser4 | MhxzKhl8758 |
| testUser5 | MhxzKhl112 |
如果想自己設置初始化的用戶名信息,可以參考代碼來自己生成用戶:
src/main/java/com/baidu/disconf/web/tools/UserCreateTools.java
部署War
修改server.xml文件,在Host結點下設定Context:
<Context path="" docBase="/home/work/dsp/disconf-rd/war"></Context>
并設置端口為 8015
啟動Tomcat,即可。
部署 前端
修改 nginx.conf
upstream disconf {
server 127.0.0.1:8015;
}
server {
listen 80;
server_name localhost;
access_log /home/work/var/logs/disconf/access.log;
error_log /home/work/var/logs/disconf/error.log;
location / {
root /home/work/dsp/disconf-rd/war/html;
if ($query_string) {
expires max;
}
}
location ~ ^/(api|export) {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://localhost;
}
}
關于host
這里的 host 設置成 localhost (可以自定義),但它 必須與 application.properties 里的domain一樣。
然后瀏覽器的訪問域名也是這個。
新建app

新建配置項


新增配置文件

以config1.properties舉例:
uid=1
password=4
username=www2

客戶端
引入
<dependency>
<groupId>com.baidu.disconf</groupId>
<artifactId>disconf-client</artifactId>
<version>2.6.36</version>
</dependency>
基于xml的分布式配置
第一步:撰寫配置文件
<bean id="disconfMgrBean" class="com.baidu.disconf.client.DisconfMgrBean"
destroy-method="destroy">
<property name="scanPackage" value="com.absurd"/>
</bean>
<bean id="disconfMgrBean2" class="com.baidu.disconf.client.DisconfMgrBeanSecond"
init-method="init" destroy-method="destroy">
</bean>
<context:component-scan base-package="com.absurd"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
第二步:撰寫disconf.properties
# 是否使用遠程配置文件
# true(默認)會從遠程獲取配置 false則直接獲取本地配置
enable.remote.conf=true
#
# 配置服務器的 HOST,用逗號分隔 127.0.0.1:8000,127.0.0.1:8000
#
conf_server_host=localhost
# 版本, 請采用 X_X_X_X 格式
version=1_0_0_0
# APP 請采用 產(chǎn)品線_服務名 格式
app=absurd-app
# 環(huán)境
env=rd
# debug
debug=true
# 忽略哪些分布式配置,用逗號分隔
ignore=
# 獲取遠程配置 重試次數(shù),默認是3次
conf_server_url_retry_times=1
# 獲取遠程配置 重試時休眠時間,默認是5秒
conf_server_url_retry_sleep_seconds=1
第三步:撰寫配置類
以config1.properties舉例:
@Service
@Scope("singleton")
@DisconfFile(filename = "config1.properties")
public class OneConfig {
private Long uid;
private String username;
private String password;
@DisconfFileItem(name = "uid", associateField = "uid")
public Long getUid() {
return uid;
}
public void setUid(Long uid) {
this.uid = uid;
}
@DisconfFileItem(name = "username", associateField = "username")
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@DisconfFileItem(name = "password", associateField = "password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
上面這種寫法是托管配置,通過簡單的注解類方式 托管配置。托管后,本地不需要此配置文件,統(tǒng)一從配置中心服務獲取。
當配置被更新后,注解類的數(shù)據(jù)通過@Service實現(xiàn)自動同步。
** 變量分布式配置 **
@Service
@Scope("singleton")
public class OneKeyConfig {
private Long key;
@DisconfItem(key = "absurd-app-rd-1")
public Long getKey() {
return key;
}
}
靜態(tài)配置
@DisconfFile(filename = "config1.properties")
public class OneStaticConfig {
private static Long uid;
private static String username;
private static String password;
@DisconfFileItem(name = "uid", associateField = "uid")
public static Long getUid() {
return uid;
}
@DisconfFileItem(name = "username", associateField = "username")
public static String getUsername() {
return username;
}
@DisconfFileItem(name = "password", associateField = "password")
public static String getPassword() {
return password;
}
}
配置更新的通知
實現(xiàn)IDisconfUpdate 接口的reload方法,注意這里此類必須是JavaBean,Spring托管的,且 “scope” 都必須是singleton的。
添加 @DisconfUpdateService 注解,classes 值加上 OneConfig.class ,表示當 JedisConfig.class 這個配置文件更新時,此回調(diào)類將會被調(diào)用?;蛘撸褂?confFileKeys 也可以。
@Service
@Scope("singleton")
@DisconfFile(filename = "config1.properties")
@DisconfUpdateService(classes = {OneConfig.class})
public class OneConfig implements IDisconfUpdate {
Logger logger = LoggerFactory.getLogger(getClass());
private Long uid;
private String username;
private String password;
@DisconfFileItem(name = "uid", associateField = "uid")
public Long getUid() {
return uid;
}
public void setUid(Long uid) {
this.uid = uid;
}
@DisconfFileItem(name = "username", associateField = "username")
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@DisconfFileItem(name = "password", associateField = "password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void reload() throws Exception {
logger.info(">>>>>>>>>>配置已改變>>>>>>>>>>>>");
}
}
當然也可以單獨抽出來寫一個類
基于xml配置
- 可以自動reload
<bean id="configproperties_disconf" class="com.baidu.disconf.client.addons.properties.ReloadablePropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:config2.properties</value>
</list>
</property>
</bean>
<bean id="propertyConfigurer" class="com.baidu.disconf.client.addons.properties.ReloadingPropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="propertiesArray" >
<list>
<ref bean="configproperties_disconf"/>
</list>
</property>
</bean>
如果有 <context:property-placeholder location="classpath*:properties/*.properties"/>必須去掉否則會報錯
- 不可以自動reload
<!-- 使用托管方式的disconf配置(無代碼侵入, 配置更改不會自動reload)-->
<bean id="configproperties_no_reloadable_disconf"
class="com.baidu.disconf.client.addons.properties.ReloadablePropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:config2.properties</value>
</list>
</property>
</bean>
<bean id="propertyConfigurerForProject1"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="propertiesArray">
<list>
<ref bean="configproperties_no_reloadable_disconf"/>
</list>
</property>
</bean>
過濾要進行托管的配置
忽略哪些分布式配置,用逗號分隔
ignore=jdbc-mysql.properties