功能特点:
支持配置的分布式化管理,配置发布统一化 极简的使用方式(注解式编程 或 XML代码无代码侵入模式) 需要Spring编程环境
架构设计:
每个模块的简单介绍:
Disconf-core 分布式通知模块:支持配置更新的实时化通知路径管理模块:统一管理内部配置路径URLDisconf-client 配置仓库容器模块:统一管理用户实例中本地配置文件和配置项的内存数据存储配置reload模块:监控本地配置文件的变动,并自动reload到指定bean扫描模块:支持扫描所有disconf注解的类和域下载模块:restful风格的下载配置文件和配置项watch模块:监控远程配置文件和配置项的变化主备分配模块:主备竞争结束后,统一管理主备分配与主备监控控制主备竞争模块:支持分布式环境下的主备竞争Disconf-web 配置存储模块:管理所有配置的存储和读取配置管理模块:支持配置的上传、下载、更新通知模块:当配置更新后,实时通知使用这些配置的所有实例配置自检监控模块:自动定时校验实例本地配置与中心配置是否一致权限控制:web的简单权限控制Disconf-tools context共享模块:提供多实例间context的共享install
disconf-client Install
在MAVEN POM文件加入:
<dependency> <groupId>com.baidu.disconf</groupId> <artifactId>disconf-client</artifactId> <version>2.6.36</version> </dependency>disconf-web Install
安装依赖的软件:
安装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)准备配置
将你的配置文件放到此地址目录下(以下地址可自行设定):
/home/work/dsp/disconf-rd/online-resources如果不确定如何配置,可以拷贝/disconf-web/profile/rd/目录下的文件,拷贝过去后修改即可。
配置文件包括:
- jdbc-mysql.properties (数据库配置) - redis-config.properties (Redis配置,主要用于web登录使用) - zoo.properties (Zookeeper配置) - application.properties (应用配置)注意,记得执行将application-demo.properties复制成application.properties:
cp application-demo.properties application.properties运行前初始化工作
初始化数据库,里面默认有6个用户(请注意线上环境删除这些用户以避免潜在的安全问题)
如果想自己设置初始化的用户名信息,可以参考代码来自己生成用户:
src/main/java/com/baidu/disconf/web/tools/UserCreateTools.java修改server.xml文件,在Host结点下设定Context:
<Context path="" docBase="/home/work/dsp/disconf-rd/war"></Context>并设置端口为 8015
启动Tomcat,即可。
Demo_一个简单的Redis程序:
我们需要一个 redis.properties 文件,里面含有 Host 和 Port。文件内容是:
redis.host=127.0.0.1 redis.port=6379我们需要把此文件放在项目的ClassPath路径下。
我们撰写一个类JedisConfig,它与 redis.properties 相对应。整个类的完整代码如下:
package com.example.disconf.demo.config; import org.springframework.stereotype.Service; /** * Redis配置文件 * * @author liaoqiqi * @version 2014-6-17 */ @Service @Scope("singleton") public class JedisConfig { // 代表连接地址 private String host; // 代表连接port private int port; /** * 地址 * * @return */ public String getHost() { return host; } public void setHost(String host) { this.host = host; } /** * 端口 * * @return */ public int getPort() { return port; } public void setPort(int port) { this.port = port; } }注意,这里的Get&Set方法均是Eclipse自动生成的。
在applicationContext.xml 添加以下代码,目的是将配置值注入到此类中:
<bean id="propertyConfigurerForProject1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="order" value="1" /> <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /> <property name="ignoreResourceNotFound" value="true" /> <property name="ignoreUnresolvablePlaceholders" value="true" /> <property name="locations"> <list> <value>classpath*:/redis.properties</value> </list> </property> </bean> <bean id="jedisConfig" class="com.example.disconf.demo.config.JedisConfig"> <property name="host" value="${redis.host}" /> <property name="port" value="${redis.port}" /> </bean>我们的初衷是使用Redis服务。因此,我们需要撰写一个连接Redis的Service类,它使用的是第二步里的配置文件类。完整类的实现代码如下:
package com.example.disconf.demo.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import redis.clients.jedis.Jedis; import com.example.disconf.demo.config.JedisConfig; import com.example.disconf.demo.utils.JedisUtil; /** * 一个简单的Redis服务 * * @author liaoqiqi * @version 2014-6-17 */ @Service @Scope("singleton") public class SimpleRedisService implements InitializingBean, DisposableBean { protected static final Logger LOGGER = LoggerFactory .getLogger(SimpleRedisService.class); // jedis 实例 private Jedis jedis = null; /** * 分布式配置 */ @Autowired private JedisConfig jedisConfig; /** * 关闭 */ public void destroy() throws Exception { if (jedis != null) { jedis.disconnect(); } } /** * 进行连接 */ public void afterPropertiesSet() throws Exception { jedis = JedisUtil.createJedis(jedisConfig.getHost(), jedisConfig.getPort()); } /** * 获取一个值 * * @param key * @return */ public String getKey(String key) { if (jedis != null) { return jedis.get(key); } return null; } }具体步骤是:
此类实现了 InitializingBean, DisposableBean 两个接口,目的是在Bean初始化后进行Redis的连接。为此类添加 @Service ,代表它是一个Bean。Spring托管的,且 “scope” 都必须是singleton的。使用起来非常简单, 示例如下:
package com.example.disconf.demo.task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.disconf.demo.config.JedisConfig; import com.example.disconf.demo.service.SimpleRedisService; /** * 演示分布式配置文件、分布式配置的更新Demo * * @author liaoqiqi * @version 2014-6-17 */ @Service public class DisconfDemoTask { protected static final Logger LOGGER = LoggerFactory .getLogger(DisconfDemoTask.class); @Autowired private SimpleRedisService simpleRedisService; @Autowired private JedisConfig jedisConfig; private static final String REDIS_KEY = "disconf_key"; /** * */ public int run() { try { while (true) { Thread.sleep(5000); LOGGER.info("redis( " + jedisConfig.getHost() + "," + jedisConfig.getPort() + ") get key: " + REDIS_KEY } } catch (Exception e) { LOGGER.error(e.toString(), e); } return 0; } }在applicationContext.xml里添加Bean定义:
<!-- 使用disconf必须添加以下配置 --> <bean id="disconfMgrBean" class="com.baidu.disconf.client.DisconfMgrBean" destroy-method="destroy"> <property name="scanPackage" value="com.example.disconf.demo"/> </bean> <bean id="disconfMgrBean2" class="com.baidu.disconf.client.DisconfMgrBeanSecond" init-method="init" destroy-method="destroy"> </bean> 其中这里,我们定义 属性“scanPackage” 的值是 com.example.disconf.demo。 这里需要填上你的项目的Package名。这与Spring的auto scan包名功能一样。另外,从2.6.23起,这里的 scanPackage 属性支持扫描多包,逗号分隔,例如:
<bean id="disconfMgrBean" class="com.baidu.disconf.client.DisconfMgrBean" destroy-method="destroy"> <property name="scanPackage" value="com.example.disconf.demo,com.example.disconf.demo2"/> </bean>你的项目的扫描类是com.example,为了支持disconf,因此,必须添加扫描类 com.baidu ,如:
<context:component-scan base-package="com.baidu,com.example"/>注:从版本2.6.30开始,不再需要扫描包com.baidu了,扫描自己的包即可。即:
<context:component-scan base-package="com.example"/>使你的项目支持 cglib的aop
<aop:aspectj-autoproxy proxy-target-class="true"/>我们撰写一个类JedisConfig,它与 redis.properties 相对应。整个类的完整代码如下:
package com.example.disconf.demo.config; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import com.baidu.disconf.client.common.annotations.DisconfFile; import com.baidu.disconf.client.common.annotations.DisconfFileItem; /** * Redis配置文件 * * @author liaoqiqi * @version 2014-6-17 */ @Service @Scope("singleton") @DisconfFile(filename = "redis.properties") public class JedisConfig { // 代表连接地址 private String host; // 代表连接port private int port; /** * 地址, 分布式文件配置 * * @return */ @DisconfFileItem(name = "redis.host", associateField = "host") public String getHost() { return host; } public void setHost(String host) { this.host = host; } /** * 端口, 分布式文件配置 * * @return */ @DisconfFileItem(name = "redis.port", associateField = "port") public int getPort() { return port; } public void setPort(int port) { this.port = port; } }具体步骤是:
为这个类 JedisConfig 定义 @DisconfFile 注解,必须指定文件名为 redis.properties 。定义域 host port,分别表示Host和Port。并使用Eclipse为其自动生成 get&set 方法。为这两个域的get方法上添加注解 @DisconfFileItem 。添加标记 name, 表示配置文件中的KEY名,这是必填的。标记associateField是可选的,它表示此get方法相关连的域的名字,如果此标记未填,则系统会自动分析get方法,猜测其相对应于域名。强烈建议添加associateField标记,这样就可以避免Eclipse生成的Get/Set方法不符合Java规范的问题。标记它为Spring托管的类 (使用@Service),且 “scope” 都必须是singleton的。注意:
Eclipse自动生成的get方法,可能与Java的规范不同。这会导致很多问题。因此,建议加上 associateField 标记。
准备disconf.properties文件:
Disconf启动需要此文件,文件示例是:
# 是否使用远程配置文件 # true(默认)会从远程获取配置 false则直接获取本地配置 enable.remote.conf=true # # 配置服务器的 HOST,用逗号分隔 127.0.0.1:8000,127.0.0.1:8000 # conf_server_host=127.0.0.1:8080 # 版本, 请采用 X_X_X_X 格式 version=1_0_0_0 # APP 请采用 产品线_服务名 格式 app=disconf_demo # 环境 env=rd # debug debug=true # 忽略哪些分布式配置,用逗号分隔 ignore= # 获取远程配置 重试次数,默认是3次 conf_server_url_retry_times=1 # 获取远程配置 重试时休眠时间,默认是5秒 conf_server_url_retry_sleep_seconds=1配置相关说明可参考:配置
注意:如果使用Disconf,则本地的配置文件redis.properties可以删除掉(也可以不删除掉,建议删除掉)。如果不使用Disconf,则需要此配置文件。
当你的程序启动时,disconf就会帮忙你的程序去获取配置文件。那如何让disconf知道你的配置呢?答案是需要在disconf-web上传配置文件哦。
点击主页面的新建配置文件按钮:
进入页面后就可以上传 配置文件了
你在第五步上传了配置文件 redis.properties ,那么 ,当你的程序启动时,disconf就会帮忙你的程序去获取配置文件。
可以看到已经有一个实例在使用redis.properties了。
点击查看它的详情,可以看到,确实是我的实例在使用它。
至此,分布式配置文件的撰写就已经写完了。
可以看到,基于注解的方式,不需要在xml定义 java bean(config类).
大家可以看到,第一次使用时,需要
在applicationContext.xml添加Disconf启动支持使用注解方式 修改配置类添加disconf.properties在disconf-web上上传配置文件非第一次使用时,需要
使用注解方式 修改配置类在disconf-web上上传配置文件就可以支持分布式配置了。
并且,如果将 disconf.disconf.properties 中的 enable.remote.conf 设置为 false
那么,分布式配置就会失效,退化为 使用本地配置方式(即第一部分的功能)。(如果是这种情况,你必须确认你本地留有相应的配置文件。 一般来说,只要成功跑过一次基于disconf的程序,那么classpath目录下就会有此程序的所有相应配置文件。)并且,如果 disconf-web无法正常服务(conf_server_host=127.0.0.1:8080),分布式配置也会失效,退化为 使用本地配置方式(即第一部分的功能)。(如果是这种情况,你必须确认你本地留有相应的配置文件)
也就是说,Disconf是具有兼容性的
当开启Disconf时, 如果Disconf正常运行,则正常使用分布式配置。如果Disconf非正常运行,则使用本地配置。(Disconf可以保证在Disconf失败时,原有程序能够按原有逻辑正确运行)当不开启Disconf时, 则使用本地配置。注:
只要是运行一次分布式程序成功,则本地就含有最全的配置文件。此时,如果再运行一次分布式程序,如果出现失败,则上一次下载成功的配置文件就会当成本地配置生效,程序成功启动。参考官网地址连接:http://disconf.readthedocs.io/zh_CN/latest/
