Disconf使用方法(1) —— 基于注解的分布式配置文件和配置项

本文将新建一个SpringBoot示例工程,然后整合Disconf的客户端功能,最后以Redis配置为例,讲解如何通过注解实现分布式的配置文件和配置项。

一、环境描述

1. Disconf服务器

2. Spring Tool Suite

  • 版本:STS 3.9.2.RELEASE

3. Redis

二、建立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包,如下图所示:

下载Disconf依赖关系

创建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中获取的值,如下图所示:

从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-2实例中取值

这就表示配置更新回调生效了,不用重启服务就能即时生效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.xmldisconf.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

若有不清楚的地方,可以参考示例代码,再结合实际项目进行修改!