如非授权,禁止用于商业用途,转载请注明出处
作者:mynewworldyyl
往下看前,建议完成前面1到11小节
1. CuratorFramework支持
JMicro目前基于Zookeeper实现统一配置和服务注册两个微服务核心功能。
应用中可以直接使用org.apache.curator.framework.CuratorFramework操作ZK,获取CuratorFramework实例方式如下:
@Inject private CuratorFramework curator;
通过CuratorFramework获取ZK路径为path的值如下:
public String getData(String path){ //init(); GetDataBuilder getDataBuilder = this.curator.getData(); try { byte[] data = getDataBuilder.forPath(path); return new String(data,Constants.CHARSET); } catch (KeeperException.NoNodeException e) { logger.error(e.getMessage()); }catch(Exception e){ logger.error("",e); } return ""; }
2. JMicro对配置管理和服务注册接口的进一步封装
JMicro目前使用ZK做配置管理和服务注册,但并不是唯一选择,将来根据需求很可能选择更合适的实现,如ETCD凭借其强劲的性能,更简单易用的HTTP API接口,应该是一个比ZK更好的选择。
JMicro配置管理和服务注册都基于IDataOperator接口实现,代码如下:
public interface IDataOperator { void addListener(IConnectionStateChangeListener lis); void addDataListener(String path,IDataListener lis); void addChildrenListener(String path,IChildrenListener lis); void addNodeListener(String path,INodeListener lis); void removeNodeListener(String path,INodeListener lis); void removeDataListener(String path,IDataListener lis); void removeChildrenListener(String path,IChildrenListener lis); boolean exist(String path); String getData(String path); void setData(String path,String data); Set<String> getChildren(String path); void createNode(String path,String data,boolean elp); void deleteNode(String path); void init(); void objectFactoryStarted(IObjectFactory of); }
如果对Raft原理及实现有基本了解,相信大家很容易能理解以上除init和objectFactoryStarted之外的其他方法。分别抽像对结点,结点数据,子结点的基本操作。
init方法对实现做初始化,如org.jmicro.zk.ZKDataOperator中的实现如下:
public void init(){ if(isInit){ return; } isInit = true; propes = new Properties(); curator = createCuratorFramework(); }
创建CuratorFramework实例。
而objectFactoryStarted则在IObjectFactory实例启动时,将CuratorFramework实例注册到IObjectFactory中,以方便需要直接操作ZK的模块实现。代码如下:
@Override public void objectFactoryStarted(IObjectFactory of) { of.regist(CuratorFramework.class, curator);}
正因为有以上代码,才使得
@Inject private CuratorFramework curator;
通过@Inject注解注入CuratorFramework实例得以实现。
3. org.jmicro.api.raft.IDataOperator基本使用
过通IDataOperator接口,将来无论底层Raft实现怎么改变,应用都不需要修改。但是如果应用依赖于CuratorFramework操作ZK,并且Raft切换到Etcd,则实现代码需要同步调整,所以在JMicro环境下做应用,如果能用IDataOperator实现的功能,不建议使用CuratorFramework。
完整的实现代码请参数org.jmicro.zk.ZKDataOperator。
IDataOperator实现特性:
a. 监听器只需要设置一次,就可以对结点做永久监听,除非用户主动删除监听器,如果使用CuratorFramework或ZK原生客户端,则需要重复设置监听器;
b. CuratorFramework或ZK原生客户端取数据时,得到的是byte数组,而IDataOperator得到的是UTF8编码的字符串;
c. 数据缓存功能,如判断某个结点是否存在,不会每次都去请求查询ZK,只要本地缓存能查询到即说明结点存在,只有结点不存时,才会去ZK中查询;
d. 创建结点时,首先判断结点是否已经存在,如果已经存在,则直接设置结点数据,但如果结点是瞬时结点,则会抛出异常,而不是设置其为最新数据;
e. 创建结点时,如果叶子结点的父背结点还不存在,则会先创建父背结点,最后才创建叶子结点及其数据。
样例:
如下代码获取一个路由规则(第3行)并监听这个路由规则变化(第7,12行)
private RouteRule updateOne(String c) { String p = RULE_DIR+"/"+c; String data = this.dataOperator.getData(p); RouteRule rule = JsonUtils.getIns().fromJson(data, RouteRule.class); rule.setId(c); rule.check(); watchRule(p); return rule; } private void watchRule(String p) { this.dataOperator.addDataListener(p, dataListener); }
同一个监听器如果增加了多次,效果相同。但是ZK原生实现会增加多个监听,并且收到多个通知,而JMIcro实现则不会。
以下代码做熔断服务操作(第11行),第9行设置熔断标记
public void breakService(ServiceMethod sm) { String path = ServiceItem.pathForKey(sm.getKey().getUsk().toKey(true, true, true)); ServiceItem item = this.path2SrvItems.get(path); if(item == null) { logger.error("Service [{}] not found",path); return; } ServiceMethod sm1 = item.getMethod(sm.getKey().getMethod(), sm.getKey().getParamsStr()); sm1.setBreaking(sm.isBreaking()); if(dataOperator.exist(path)){ dataOperator.setData(path,JsonUtils.getIns().toJson(item)); } }
4. JMicro配置ZOOKEEPER连接信息
JMicro默认只支持ZK本地单机模式,主机是127.0.0.1或localhost,端口是2181。
可以通过命令行参数,环境变量,/META-INF/jmicro/*.properties配置,命令行参数方式如下:
java -jar target/jmicro.example.provider-0.0.1-SNAPSHOT-jar-with-dependencies.jar -DregistryUrl=zookeeper://127.0.0.1:2181,zookeeper://127.0.0.1:2182,zookeeper://127.0.0.1:2183
properties配置方式如下:
registryUrl=zookeeper://127.0.0.1:2181,zookeeper://127.0.0.1:2182,zookeeper://127.0.0.1:2183
windows环境变量配置方式如下:
应用可以根据需要通过以上3个方式进行配置。