Super-diamond是在淘宝diamond基础上改良而来,是一套优秀的配置管理服务器,由于工作中需要用到,就简单学习了一下,并将其记录下来,源码地址点击这里下载
先上一张服务流程图,画的简陋请包涵
这里写图片描述


  • 主要功能
    - 配置管理系统提供系统参数配置管理,例如数据库的配置信息等,配置参数修改以后可以实时推送到客户端(基于netty4), 方便系统动态修改运行参数。
    - 可以建多个项目,每个项目分为三种profile场景(development、test、production)。
    - 所有参数均由development profile配置,test和production profile继承development profile配置,也可以覆盖其配置。 test和production profile只提供修改功能。
    - client 备份配置信息到本地文件系统,如果server不可用,可以使用本地备份。client 能够定时重连server,保证client高可用。
    - client 提供ConfigurationListener,当某个属性发生变化(add、update、clear), ConfigurationListener能够接收到ConfigurationEvent,作相应的触发事件进行处理。
    - server 备份配置文件系统系统,如果数据库不用,能够保证对客户端提供数据(待完善)。
  • 目录结构
    导入编辑器后,目录结构如下
    这里写图片描述
    一个是客户端,一个是服务端,客户端即在你需要的项目pom文件中加入依赖,前提是你需要先将其安装到maven仓库中,可以在项目根目录下执行

mvn clean install

如果得到的就是jar包,可以执行命令进行安装到本地仓库

mvn install:install-file -DgroupId=com.github.diamond  -DartifactId=super-diamond-client -Dversion=1.2.1-SNAPSHOT -Dpackaging=jar -Dfile="你的jar所在全路径"

然后加入依赖:
这里写图片描述

如果懒得安装,也可以放在WEB-INF的lib文件夹下,在依赖中加入引用,例如

<dependency>  
            <groupId> com.github.diamond </groupId >  
            <artifactId> super-diamond-client </artifactId >  
            <version> 1.2.1-SNAPSHOT </version >  
            <scope> system </scope >  
            <systemPath> ${basedir}/src/main/webapp/WEB-INF/lib/super-diamond-client-1.2.1-SNAPSHOT.jar
            </systemPath >  
</dependency>

这是客户端,服务端你可以打包后安装在某服务器上提供服务,下面再具体说下怎么应用。

  • 服务端安装
  • super-diamond-server 安装
  1. 进入super-diamond目录,构建super-diamond父工程: mvn install,同时客户端也安装到了本地仓库。
  2. super-diamond-server中嵌入jetty运行,构建部署包:mvn install assembly:single -Pproduction,生成super-diamond-server-${version}-bin.tar.gz文件,放上服务器进行解压,运行bin/server.sh start命令。
  3. 在conf\META-INF\scripts目录中,提供mysql和oracle建表脚本,理论也支持其它数据库,在conf\META-INF\res\config-production.properties文件中修改数据库配置。
  4. 在conf_user表中添加用户admin,密码000000的加密值为:670b14728ad9902aecba32e22fa4f6bd, mysql脚本:
    insert into conf_user(id,USER_code,USER_NAME,PASSWORD,CREATE_TIME) values(1,‘admin’,‘admin’,‘670b14728ad9902aecba32e22fa4f6bd’,current_timestamp() );
    commit;
  5. 访问super-diamond-server,jetty默认端口为8090,可以在:conf/META-INF/res/jetty.properties中修改。
    http://localhost:8090/superdiamond

启动的时候如果提示端口占用,可以修改默认端口,比如我将jetty默认端口(8090)修改为8000(上述第五条有告诉在哪修改),将netty的默认端口(8283)修改为8284,在配置文件config-production.properties中修改。
当然我是部署后发现端口被占用才改的,你们如果没有这个问题可以忽略上述。

打包后,得到
这里写图片描述
再部署服务器上进行解压运行

tar -xvf super-diamond-server-1.1.0-SNAPSHOT-bin.tar.gz

访问地址:http://localhost:8000/superdiamond(注意端口,此处是我修改后的)
这里写图片描述

  • super-diamond-client 客户端定义服务端参数的几种方式
    客户端测试涉及到连接到diamond服务端参数怎么初始化的问题,现在提供了以下几种方式:
  1. 固定在diamond客户端配置文件中,但这种方式显然不好,因为diamond客户端是以jar的形式被其他项目所依赖,修改配置比较麻烦,每次都累重新打包,还得需要源码
  2. 通过环境变量和jvm参数两种方式设置,避免固定在工程配置中
export SUPERDIAMOND_PROJCODE=javademo
export SUPERDIAMOND_PROFILE=production
export SUPERDIAMOND_MODULES=jdbc,common #多个模块之用逗号分隔,可以设置为空,获取所有模块配置。
export SPUERDIAMOND_HOST=192.168.0.1
export SPUERDIAMOND_PORT=8283

或者

-Dsuperdiamond.projcode=my-test1 -Dsuperdiamond.profile=production -Dsuperdiamond.modules=模块1 -Dspuerdiamond.host=127.0.0.1 -Dspuerdiamond.port=8284

本人本地测试选择第二种方式,如:
这里写图片描述
,如果后面项目部署在服务器上,可以放在tomcat启动脚本里,如:

JAVA_OPTS="$JAVA_OPTS -Dsuperdiamond.projcode=desktop -Dsuperdiamond.host=172.31.7.176 -Dsuperdiamond.port=8283 -Dsuperdiamond.profile=test"
3.spring配置文件加载,道理和第1种一样,不推荐,测试阶段可以有。    
<bean id="propertiesConfiguration" class="com.github.diamond.client.PropertiesConfigurationFactoryBean">
		<constructor-arg index="0" value="192.168.58.127" />
		<constructor-arg index="1" value="8284" />
		<constructor-arg index="2" value="my-test1" />
		<constructor-arg index="3" value="production" />
		<constructor-arg index="4" value="模块1" />
</bean>

连接服务参数搞清楚后,我们就可以测试了,在super-diamond-client里test目录下有详细测试方法,我就简单验证下远程参数获取,和参数改变触发的自定义监听事件

  • 服务测试

  • 远程参数获取
    这是服务端配置的
    这里写图片描述
    下面是客户端获取参数测试
    这里写图片描述

    上面的是主动调用属性配置器的get方法进行获取,下面也可以通过将自定义的属性配置器(需要实现FactoryBean)放入PropertySourcesPlaceholderConfigurer的property 属性中(该属性是个数组,支持多条配置文件加载),通过${key}方式获取,如:
    这里写图片描述

上图配置文件bean为testBean的url属性在加载初始化入spring容器中时,通过${config-jdbc.url}获取了远程配置的值,运行结果如下:
这里写图片描述

注:PropertyPlaceholderConfigurer是个bean工厂后置处理器的实现,也就是 BeanFactoryPostProcessor接口的一个实现。
PropertyPlaceholderConfigurer可以将上下文(配置文 件)中的属性值放在另一个单独的标准java Properties文件中去。
在XML文件中用${key}替换指定的properties文件中的值。这样的话,只需要对properties文件进 行修改,而不用对xml配置文件进行修改
  • 触发监听事件
    首先我们启动客户端
    这里写图片描述

什么都没有发生,当前config-jdbc.url我们配置的值是127.0.0.1,现在去服务端操作界面,将其改为127.0.0.2
这里写图片描述

再来看下客户端发生了什么:
这里写图片描述
客户端会得知参数被修改了并自动触发事件,至于事件做什么可以根据需求自定义。下面我简单解读了下代码,不关注原理的话这篇文章看到这就可以了。

通过对netty的研究,我们可以知道服务修改后为什么客户端会有触发,其实主要归功于netty的SimpleChannelInboundHandler这个请求的处理类,在netty服务端启动的时候会指定一个处理器
这里写图片描述
,这个处理器我们可以自定义,通过重写netty的channelRead0方法,我们可以自定义一些逻辑处理,该方法支持获取每次请求的通道上下文和请求参数,通过定义变量clients和channels

public static ConcurrentHashMap<ClientKey /*projcode+profile*/, List<ClientInfo> /*client address*/> clients = 
			new ConcurrentHashMap<ClientKey, List<ClientInfo>>();
private ConcurrentHashMap<String /*client address*/, ChannelHandlerContext> channels = 
			new ConcurrentHashMap<String, ChannelHandlerContext>();

这里写图片描述

来存储每次请求的客户端信息,如ip,请求参数(即projCode、modules等)等,这样,在修改配置时可以匹配到相应的客户端进行通知。
并且,ChannelInboundHandlerAdapter类的另一个方法channelInactive,可以实现在客户端与服务端将要断开连接时,删除相应的的客户端信息,避免无谓的通知。
这里写图片描述

同时,客户端在启动的时候也会加载一个处理器
这里写图片描述

这个ClientChannelInitializer在通道初始化时选择的处理事件用的的是自定义的Netty4ClientHandler,看一下该类的构造
这里写图片描述

最后再配和项目启动时初始化PropertiesConfiguration这个bean时,构造器初始化时会启动对服务端的连接,
这里写图片描述
这个方法在启动时会初始化一个单线程化的线程池,是一个死循环不断的读取上面说的阻塞队列,获取后进行一些操作,如触发自定义的监听事件,从而实现了服务端改个参数,有关联的客户端都会收到更新消息,及执行自定义的一些事件。
这里写图片描述

ok,关于 super-diamond就了解到这,这个服务是基于淘宝的diamond进行改造来的,有一些特性,我也没介绍了,比如说服务配置信息的本地化,如果数据库连不上服务端可以正常读取参数,或者服务端连不上,客户端也会对原先在本地存储的配置信息文件进行读取
这里写图片描述

其他还有什么问题,大家可以下载源码进行解读。


See you in the next article !

Logo

快速构建 Web 应用程序

更多推荐