Super-diamond是在淘宝diamond基础上改良而来,是一套优秀的配置管理服务器,由于工作中需要用到,就简单学习了一下,并将其记录下来,源码地址点击这里下载
先上一张服务流程图,画的简陋请包涵
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文件夹下,在依赖中加入引用,例如
com.github.diamond
super-diamond-client
1.2.1-SNAPSHOT
system
${basedir}/src/main/webapp/WEB-INF/lib/super-diamond-client-1.2.1-SNAPSHOT.jar
这是客户端,服务端你可以打包后安装在某服务器上提供服务,下面再具体说下怎么应用。
启动的时候如果提示端口占用,可以修改默认端口,比如我将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(注意端口,此处是我修改后的)
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种一样,不推荐,测试阶段可以有。
连接服务参数搞清楚后,我们就可以测试了,在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 !