本文将新建一个SpringBoot示例工程,然后整合Disconf的客户端功能,最后以Redis配置为例,讲解如何通过注解实现分布式的配置文件和配置项。
一、环境描述
1. Disconf服务器
- 控制台:http://10.15.1.21:8080/
- 安装方法:参考《如何容器化部署Disconf统一配置服务》
2. Spring Tool Suite
- 版本:STS 3.9.2.RELEASE
3. Redis
- IP:192.168.190.128
- 端口(实例-1):6379
- 端口(实例-2):6380
- 安装方法:参考《Redis的Docker镜像制作详解》
二、建立SpringBoot示例工程
通过STS建立SpringBoot的示例工程,名称为disconf-atnt-demo
。本文采用的配置如下:
- SpringBoot版本为2.0.1
- 项目依赖关系选择Web
具体的创建步骤,本文不再详述。
三、整合Disconf客户端
打开pom.xml
文件,添加disconf-client的依赖关系,如下所示:
<dependency>
<groupId>com.baidu.disconf</groupId>
<artifactId>disconf-client</artifactId>
<version>2.6.36</version>
</dependency>
示例工程会自动下载Disconf客户端的jar包,如下图所示:
创建spring-disconf.xml
文件,让Spring管理Disconf管理器的Bean实例,必须添加以下配置:
<bean id="disconfMgrBean" class="com.baidu.disconf.client.DisconfMgrBean"
destroy-method="destroy">
<property name="scanPackage" value="com.example.demo.inst,com.example.demo.stc" />
</bean>
<bean id="disconfMgrBean2" class="com.baidu.disconf.client.DisconfMgrBeanSecond"
init-method="init" destroy-method="destroy">
</bean>
其中,属性“scanPackage”的值是“com.example.demo.inst,com.example.demo.stc”,
这里需要填写工程里需要扫描的Package名。“scanPackage”属性支持扫描多个包,使用逗号分隔。
在disconf-atnt-demo
工程的启动类DisconfAtntDemoApplication
中引入spring-disconf.xml
配置文件,关键代码如下所示:
@SpringBootApplication
@ImportResource({"classpath:spring-disconf.xml"})
public class DisconfAtntDemoApplication {
public static void main(String[] args) {
SpringApplication.run(DisconfAtntDemoApplication.class, args);
}
}
创建disconf.properties
文件,指定Disconf的一些配置,内容如下所示:
disconf.enable.remote.conf=true
disconf.conf_server_host=10.15.1.21:8080
disconf.version=1_0_0_0
disconf.app=disconf-atnt-demo
disconf.env=rd
disconf.ignore=
disconf.conf_server_url_retry_times=2
disconf.conf_server_url_retry_sleep_seconds=1
disconf.enable_local_download_dir_in_class_path=true
各个配置项的意义,将会在第六章详细介绍。
最后,在Disconf服务器上创建一个名为disconf-atnt-demo
的应用,这个名称和上面配置文件中的disconf.app
的取值相同。
四、将配置注入成员变量
Disconf可以将配置文件中的配置项作为类的成员变量注入至业务系统,同时也支持独立的配置项,此外还具有配置更新回调的功能。
1. 配置文件
在Disconf服务器的disconf-atnt-demo
应用的rd环境中,新建一个名为instance-redis.properties
的Redis配置文件,内容如下:
redis.host=192.168.190.128
redis.port=6379
在disconf-atnt-demo
工程中,新建InstanceJedisConfig
配置类,关键代码如下:
@Component
@Scope("singleton")
@DisconfFile(filename = "instance-redis.properties")
public class InstanceJedisConfig {
private String host;
private int port;
@DisconfFileItem(name = "redis.host", associateField = "host")
public String getHost() {
return host;
}
@DisconfFileItem(name = "redis.port", associateField = "port")
public int getPort() {
return port;
}
}
此处,使用两个Disconf注解:
-
@DisconfFile
作用于类,表示这个类是instance-redis.properties
文件的配置类。 -
@DisconfFileItem
作用于成员变量,表示这个成员变量对应于配置文件中的哪个配置项。
2. 配置项
在Disconf服务器的disconf-atnt-demo
应用的rd环境中,新建一个名为“的独立配置项,内容如下:
instant - redis cannot find this k-v pair ...
在InstanceRedisService
类中,新增一个名为instantMessage
的成员变量,以及它的Getter方法,如下所示:
private String instantMessage;
@DisconfItem(key="instant.message")
public String getInstantMessage() {
return instantMessage;
}
此处,使用一个Disconf注解:
- @DisconfItem
表示instantMessage
成员变量对应于instant.message
配置项。
3. 配置更新回调
在Redis-1实例中新建一个Key-Value对:
Key=test_key
value=test_value
启动disconf-atnt-demo
工程,在浏览器中访问:
http://127.0.0.1:8080/inst/get.do?key=test_key
可以在浏览器上看到从Redis-1中获取的值,如下图所示:
从上图可以看到Disconf中的Redis连接配置生效了,顺利地从Redis中取出值。
此时,若由于一些原因(例如宕机)导致需要切换到另一个Redis实例上,那么就需要修改Redis的连接配置。传统的方法有两个缺点:
- 需要把所有应用服务器的Redis配置文件都修改一遍,效率很低。
- Redis配置文件修改完成之后,需要重启应用才能生效,导致业务不连续。
通过Disconf的分布式配置文件和配置更新回调功能,我们可以做到:
- 只需要在Disconf中修改文件,然后自动推送至每个应用服务器。
- 不用重启应用服务器,系统会自动重新加载配置,配置即刻生效。
在disconf-atnt-demo
工程中,新增一个回调类InstanceRedisServiceUpdateCallback
,关键代码如下所示:
@Component
@Scope("singleton")
@DisconfUpdateService(classes = {InstanceJedisConfig.class})
public class InstanceRedisServiceUpdateCallback implements IDisconfUpdate {
protected static final Logger LOGGER = LoggerFactory.getLogger(InstanceRedisServiceUpdateCallback.class);
@Autowired
private InstanceRedisService instanceRedisService;
public void reload() throws Exception {
instanceRedisService.changeJedis();
}
}
此处,需要注意两点:
-
@DisconfUpdateService注解
通过这个注解来监听配置信息的更新事件,它有三种取值:classes,对应配置类;confFileKeys,对应配置文件;itemKeys,对应独立配置项。配置类、配置文件和独立配置项都可以指定为列表,用逗号分隔。 -
IDisconfUpdate接口
必须继承这个接口,并且实现reload方法,否则配置更新之后就无法触发回调动作。
reload方法会调用instanceRedisService的changeJedis方法,重建Jedis连接。
在Disconf服务器中,修改instance-redis.properties
文件的redis.port
配置项,改为Redis-2实例的端口,也就是6380。注意,Redis-2实例没有test_key键值对。修改并保存之后,可以通过日志看到触发了回调的reload方法。
在浏览器中访问:
http://127.0.0.1:8080/inst/get.do?key=test_key
此时可以看到无法从Redis获取值,并且显示独立配置项中的提示信息,如下图所示:
这就表示配置更新回调生效了,不用重启服务就能即时生效Redis连接配置,业务不会中断!
五、将配置注入静态变量
Disconf还可以将配置文件中的配置项作为类的静态变量注入至业务系统,同时也支持独立的配置项,此外也具有配置更新回调的功能,这种方式和成员变量的方式极为相似,本文不再赘述。
六、客户端配置项
disconf.properties
文件的所有配置项均可以通过命令行-Dname=value
参数传入。
配置项 | 说明 | 是否必填 | 默认值 |
---|---|---|---|
disconf.conf_server_host | 配置服务器的 HOST,用逗号分隔 ,示例:127.0.0.1:8000,127.0.0.1:8000 | 是 | 必填 |
disconf.app | APP 请采用 产品线_服务名 格式 | 否 | 优先读取命令行参数,然后再读取此文件的值 |
disconf.version | 版本号, 请采用 X_X_X_X 格式 | 否 | 默认为 DEFAULT_VERSION。优先读取命令行参数,然后再读取此文件的值,最后才读取默认值。 |
disconf.enable.remote.conf | 是否使用远程配置文件,true(默认)会从远程获取配置, false则直接获取本地配置 | 否 | false |
disconf.env | 环境 | 否 | 默认为 DEFAULT_ENV。优先读取命令行参数,然后再读取此文件的值,最后才读取默认值 |
disconf.ignore | 忽略的分布式配置,用空格分隔 | 否 | 空 |
disconf.debug | 调试模式。调试模式下,ZK超时或断开连接后不会重新连接(常用于client单步debug)。非调试模式下,ZK超时或断开连接会自动重新连接。 | 否 | false |
disconf.conf_server_url_retry_times | 获取远程配置 重试次数,默认是3次 | 否 | 3 |
disconf.conf_server_url_retry_sleep_seconds | 获取远程配置 重试时休眠时间,默认是5秒 | 否 | 5 |
disconf.user_define_download_dir | 用户定义的下载文件夹, 远程文件下载后会放在这里。注意,此文件夹必须有有权限,否则无法下载到这里 | 否 | ./disconf/download |
disconf.enable_local_download_dir_in_class_path | 下载的文件会被迁移到classpath根路径下,强烈建议将此选项置为 true(默认是true) | 否 | true |
七、结语
如果现有业务系统需要引入Disconf,那么需要做一些简单的改动,大致可以归纳为以下几个步骤:
Step-1:新建配置文件,包括spring-disconf.xml
和disconf.properties
文件。
Step-2:修改启动类,引入spring-disconf.xml
文件。
Step-3:新建配置类,并使用相应的Disconf注解。
Step-4:若需要动态更新缓存和数据库配置,则需要编写回调方法。
本文的disconf-atnt-demo
示例工程,已经上传至GitLab:
http://10.15.1.248/yangbin/disconf-atnt-demo.git
若有不清楚的地方,可以参考示例代码,再结合实际项目进行修改!