SpringMVC集成Disconf(注解式分布式)

1. 注解式分布式的配置文件(最佳实践)

假设,我们的应用程序使用了Redis服务,我们将使用Jedis来进行编程。编程时,我们需要Redis的Host和Port,通常情况下,我们会把这两个参数放在配置文件里。

本教程将以两个部分来进行

第一部分讲解正常情况下(不使用Disconf)的写法,这是我们以前常做的事情 。

第二部分,会在第一部分的基础上,添加Disconf的支持。从这一部分,大家就可以看到Disconf的简洁性和低侵入性。 并且,大家也可以看到关闭和开启Disconf,原有程序(第一部分)都可以正确Work。

1.1. 第一部分:一个简单普通的Redis程序

第一步:准备一个配置文件 redis.properties

我们需要一个 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;

@Service

@Scope("singleton")

public class JedisConfig {

// 代表连接地址

private String host;

// 代表连接

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服务。因此,我们需要撰写一个连接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;

@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() throwsException {

    if (jedis != null) {

        jedis.disconnect();

    }

}

/***进行连接*/

public void afterPropertiesSet() throwsException {

    jedis = JedisUtil.createJedis(jedisConfig.getHost(), jedisConfig.getPort());

}

/***获取一个值**@paramkey*@return*/

public String getKey(String key) {

    if (jedis != null)

    {

        return jedis.get(key);

    }

    return null;

    }

}

具体步骤是:

此类实现了 InitializingBean, DisposableBean 两个接口,目的是在Bean初始化后进行Redis的连接。

为此类添加 @Service ,代表它是一个Bean。Spring托管的,且 “scope” 都必须是singleton的。

第四步:使用SimpleRedisService

使用起来非常简单, 示例如下:

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;

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

            }       

     } catch (Exception e) 

    {            

        LOGGER.error(e.toString(), e);       

     }       

     return 0;   

     }

}

1.2. 第二部分:支持分布式配置(disconf)的简单Redis程序

第一步:添加Disconf的支持

在applicationContext.xml里添加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

使你的项目支持 cglib的aop

<aop:aspectj-autoproxy proxy-target-class="true"/>

第三步:修改JedisConfig支持分布式配置

我们撰写一个类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;

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

}

@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.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-web上上传配置文件(redis.properties)

当你的程序启动时,disconf就会帮忙你的程序去获取配置文件。那如何让disconf知道你的配置呢?答案是需要在disconf-web上传配置文件哦。

点击主页面的新建配置文件按钮:

进入页面后就可以上传 配置文件了

第六步:在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时, 则使用本地配置。

注:

只要是运行一次分布式程序成功,则本地就含有最全的配置文件。此时,如果再运行一次分布式程序,如果出现失败,则上一次下载成功的配置文件就会当成本地配置生效,程序成功启动。

1.3. END

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

推荐阅读更多精彩内容