配置中心

当项目达到一定程度,配置五花八门这时候配置中心的便派上了用场。

方案1 maven打包

如果只是要区分开发环境和上线环境的配置,只要打包的时候吧不同文件环境打包进来就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功能,以便项目的开发和生成环境分离。
参考: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

客户端调用(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(分布式配置管理平台)
  • 专注于各种「分布式系统配置管理」的「通用组件」和「通用平台」, 提供统一的「配置管理服务」。
    功能特点
  • 支持配置(配置项+配置文件)的分布式化管理
  • 配置发布统一化
  • 配置发布、更新统一化:
  • 同一个上线包 无须改动配置 即可在 多个环境中(RD/QA/PRODUCTION) 上线
  • 配置存储在云端系统,用户统一管理 多个环境(RD/QA/PRODUCTION)、多个平台 的所有配置
  • 配置更新自动化:用户在平台更新配置,使用该配置的系统会自动发现该情况,并应用新配置。特殊地,如果用户为此配置定义了回调函数类,则此函数类会被自动调用。
  • 极简的使用方式(注解式编程 或 XML无代码侵入模式):我们追求的是极简的、用户编程体验良好的编程方式。目前支持两种开发模式:基于XML配置或者基于注解,即可完成复杂的配置分布式化。
  • 低侵入性或无侵入性、强兼容性:
  • 低侵入性:通过极少的注解式代码撰写,即可实现分布式配置。
  • 无侵入性:通过XML简单配置,即可实现分布式配置。
  • 强兼容性:为程序添加了分布式配置注解后,开启Disconf则使用分布式配置;若关闭Disconf则使用本地配置;若开启Disconf后disconf-web不能正常Work,则Disconf使用本地配置。
  • 支持配置项多个项目共享,支持批量处理项目配置。
  • 配置监控:平台提供自校验功能(进一步提高稳定性),可以定时校验应用系统的配置是否正确。
    注:配置项是指某个类里的某个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 (数据库配置)
  • redis-config.properties (Redis配置,主要用于web登录使用)
  • zoo.properties (Zookeeper配置)
  • application.properties (应用配置)

注意,记得执行将application-demo.properties复制成application.properties:
cp application-demo.properties application.properties

上线前的初始化工作
初始化数据库:
可以参考 sql/readme.md 来进行数据库的初始化。注意顺序执行

0-init_table.sql
1-init_data.sql
201512/20151225.sql
20160701/20160701.sql

里面默认有6个用户(请注意线上环境删除这些用户以避免潜在的安全问题

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

Paste_Image.png

新建配置项

Paste_Image.png
Paste_Image.png

新增配置文件

Paste_Image.png

以config1.properties举例:

uid=1
password=4
username=www2
Paste_Image.png

客户端

引入

<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 请采用 产品线_服务名 格式
app=absurd-app

# 环境
env=rd

# debug
debug=true

# 忽略哪些分布式配置,用逗号分隔
ignore=

# 获取远程配置 重试次数,默认是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;
    }
}

上面这种写法是托管配置,通过简单的注解类方式 托管配置。托管后,本地不需要此配置文件,统一从配置中心服务获取。

当配置被更新后,注解类的数据通过@Service实现自动同步

** 变量分布式配置 **

@Service
@Scope("singleton")
public class OneKeyConfig {
    private Long key;
    @DisconfItem(key = "absurd-app-rd-1")
    public Long getKey() {
        return key;
    }
}

静态配置

@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;
    }
}

配置更新的通知

实现IDisconfUpdate 接口的reload方法,注意这里此类必须是JavaBean,Spring托管的,且 “scope” 都必须是singleton的。
添加 @DisconfUpdateService 注解,classes 值加上 OneConfig.class ,表示当 JedisConfig.class 这个配置文件更新时,此回调类将会被调用。或者,使用 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

示例代码如下:
https://github.com/www1350/disconfig-demos

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,444评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,867评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,157评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,312评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,673评论 3 289
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,802评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,470评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,696评论 2 250
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,187评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,538评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,188评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,127评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,889评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,741评论 2 274

推荐阅读更多精彩内容