3. Tutorial 3 注解式分布式的配置项(最佳实践)

Tutorial 1 里,
我们实现了一个简单的Redis服务程序,它使用注解式的分布式配置进行管理,此Redis的配置文件存储在分布式服务器 disconf-web 上。

那如果你的配置只是一个变量,不是配置文件,怎么办?还能实现分布式配置吗?

答案当然是肯定的!

Disconf支持配置项(配置项是指 一个类的某个域变量)的分布式化。

这里以 disconf-demo 某个程序片段为例,详细介绍了 分布式的配置项 的简单示例程序。

在这里,我们将分两种情况来进行演示:

  1. 配置项在某个配置类里:外部程序通过配置类的get***方法获取。
  2. 配置项在某个Service类里。Service通过本身类的的get***方法获取。

对于这两种方式,Disconf的后台实现方式上有所不同。这里不会讲述具体原因。但是Disconf做到了兼容性,以上两种方式均支持。

3.1. 配置类里的配置项

第一步:撰写 配置项类

这里假设有一个金融系数类,它有一个折扣率变量。

package com.example.disconf.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.baidu.disconf.client.common.annotations.DisconfFile;
import com.baidu.disconf.client.common.annotations.DisconfFileItem;
import com.baidu.disconf.client.common.annotations.DisconfItem;


/**
 * 金融系数文件
 *
 **/
@Service
@DisconfFile(filename = "coefficients.properties")
public class Coefficients {

    public static final String key = "discountRate";

    @Value(value = "2.0d")
    private Double discount;


    /**
     * 折扣率,分布式配置
     *
     * @return
     */
    @DisconfItem(key = key)
    public Double getDiscount() {
        return discount;
    }

    public void setDiscount(Double discount) {
        this.discount = discount;
    }
}

具体步骤是:

  1. 编写Coefficients类,添加域 discount
  2. 用Eclipse为域discount添加 get & set方法
  3. 为get方法添加注解 @DisconfItem(key = key) ,这里的key是分布式配置项的标识,这里是 discountRate
  4. 此类必须是JavaBean,Spring托管的,且 “scope” 都必须是singleton的。
  5. 可以使用@Value为它设置一个默认值

第二步:使用此分布式配置项

撰写一个Service类,它使用 第二步里的 discountRate 变量,完整的类是:

package com.example.disconf.demo.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.baidu.disconf.client.common.annotations.DisconfItem;
import com.example.disconf.demo.config.Coefficients;

/**
 * 金融宝服务,计算一天赚多少钱
 *
 * @author liaoqiqi
 * @version 2014-5-16
 */
@Service
public class BaoBaoService {

    protected static final Logger LOGGER = LoggerFactory
            .getLogger(BaoBaoService.class);

    @Autowired
    private Coefficients coefficients;

    /**
     *
     *
     * @return
     */
    public double calcMoney() {
        return 10000 * coefficients.getDiscount();
    }

}

calcMoney()会调用 coefficients.getDiscount() 获取折扣率 来计算 真正的money.

第三步:配置项更新回调类

当配置项更新时,你的服务程序自动就会获取最新的配置项数据(不需要写回调函数,因为这里不像Redis这种较“重”的服务,这里的配置是实时生效的)。

但是,如果当你的配置项更新时,配置项本身被更新后,可能还会其它类依赖此配置项的更新,那么,你需要撰写一个回调类来获取此通知。

为了简单,这里我们以 Tutorial 2 里的 SimpleRedisServiceUpdateCallback 类 为基础,进行扩展。

假设,当此配置项被更新时,Redis也需要重新被reload,那么,你可以这样来改写 SimpleRedisServiceUpdateCallback 类,完整的代码如下:

package com.example.disconf.demo.service.callbacks;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baidu.disconf.client.common.annotations.DisconfUpdateService;
import com.baidu.disconf.client.common.update.IDisconfUpdate;
import com.example.disconf.demo.config.Coefficients;
import com.example.disconf.demo.config.JedisConfig;

/**
 * 更新Redis配置时的回调函数
 *
 * @author liaoqiqi
 * @version 2014-6-17
 */
@Service
@DisconfUpdateService(classes = { JedisConfig.class }, itemKeys = { Coefficients.key })
public class SimpleRedisServiceUpdateCallback implements IDisconfUpdate {

    protected static final Logger LOGGER = LoggerFactory
            .getLogger(SimpleRedisServiceUpdateCallback.class);

    @Autowired
    private SimpleRedisService simpleRedisService;

    /**
     *
     */
    public void reload() throws Exception {

        simpleRedisService.changeJedis();
    }

}

这里通过为注解 @DisconfUpdateService 添加一个 itemKeys: Coefficients.key ,就实现了配置项更新的通知。怎么样?是不是很强大?

第四步:在disconf-web上上传配置

上传方式是先在首页点击 新建配置项

image0

然后新建就行啦

image1

完结

通过几行简单的配置,分布式配置项 就这样添加到你的应用程序里了。

3.2. Service类的配置项

在上一节里,我们阐述了如何在 配置项类 里添加一个配置项的方法。

在本节里,我们将在上一部分的基础上,阐述如何实现 不创建配置项类 就可以 实现 分布式配置项 的方法。

准备

在 分布式配置服务器 disconf-web 上添加 moneyInvest 和 discountRate 配置项值。

第一步:撰写 含有 配置项 的Service类

在上一节里,我们撰写了一个 Coefficients.java 类,它含有 分布式配置项 discountRate,BaoBaoService.java 则是一个使用 discountRate 的服务。BaoBaoService.java 在计算(calcMoney)时,使用了固定值 10000.

在本节里,我们 将 10000 这个值动态化,标注为分布式配置项。

完整的类是:

package com.example.disconf.demo.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.baidu.disconf.client.common.annotations.DisconfItem;
import com.example.disconf.demo.config.Coefficients;

/**
 *
 * @author liaoqiqi
 * @version 2014-5-16
 */
@Service
public class BaoBaoService {

    protected static final Logger LOGGER = LoggerFactory
            .getLogger(BaoBaoService.class);

    public static final String key = "moneyInvest";

    private Double moneyInvest = 1000d;

    @Autowired
    private Coefficients coefficients;

    /**
     *
     * @return
     */
    public double calcMoney() {
        return coefficients.getDiscount()
                * getMoneyInvest();
    }

    /**
     * 投资的钱,分布式配置 <br/>
     * <br/>
     * 这里切面无法生效,因为SpringAOP不支持。<br/>
     * 但是这里还是正确的,因为我们会将值注入到Bean的值里.
     *
     * @return
     */
    @DisconfItem(key = key)
    public Double getMoneyInvest() {
        return moneyInvest;
    }

    public void setMoneyInvest(Double moneyInvest) {
        this.moneyInvest = moneyInvest;
    }

}

具体实现步骤是:

  1. 添加域 moneyInvest ,并使用Eclipse自动生成 get&set 方法。
  2. 为get方法添加 @DisconfItem 注解,并添加 key 为 moneyInvest
  3. 在函数 calcMoney() 里 调用本身类的 getMoneyInvest() 方法。
  4. 此类必须是JavaBean,Spring托管的,且 “scope” 都必须是singleton的。

第二步:在disconf-web上上传配置

这里不再赘述。

完结

只需要上面一步,就完成了分布式配置项。

配置更新也是实时的,不需要写回调函数。

service类的配置项 其实和 配置项类的配置项 撰写方法 差不多。它的好处是不需要再新建一个配置项类。