在springboot中所有的整合都是以bean的形式注入對象,從數據庫coon、redis conn、再到整合的zookeeper,依然是依照bean注入連接對象,通過zookeeper api對zookeeper中node 數據進行增刪改查等操作,從而實現配置同步。這篇文章只是初步使用web服務,在服務啟動時注冊服務,並將配置文件內容寫入zookeeper,通過api接口獲取配置內容。至於多節點配置文件同步一致性,則是以后需要深入研究的主題。
在zookeeper_caesar創建兩個模塊,core和client,core中存放zookeeper連接和相關操作方法,client是正常的web服務。在springboot分層思想中core相當於DAO層,進行zookeeper操作,在client的service層和controller層進行調用和處理。
其中client依賴core模塊,在其pom.xml中添加core模塊信息,其后在client中添加spring模塊spring-boot-starter-web(spring對servlet封裝的模塊和嵌入式tomcat)
<dependency> <groupId>com.soft.caesar</groupId> <artifactId>core</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
1.client分析
在RegistryConfig.java中創建需要的bean serviceRegistry 即zookeeper連接對象 zk = new ZooKeeper(zkServers,SESSION_TIMEOUT,this)
在TestController.java中調用serviceRestry即core中定義操作getValue,獲取zookeeper中數據
在WebListener.java中監聽web服務啟動,啟動時將服務存入zookeeper
ClientApplication.py 啟動服務主函數
2.core分析
@Component public class ServiceRegistryImpl implements ServiceRegistry,Watcher { private static CountDownLatch latch = new CountDownLatch(1); # 多線程時,等待,直到一個線程時,在latch被喚醒 private ZooKeeper zk; private static final int SESSION_TIMEOUT=5000; private static final String REGISTRY_PATH = "/registry"; public ServiceRegistryImpl() { } public ServiceRegistryImpl(String zkServers) { try { zk = new ZooKeeper(zkServers,SESSION_TIMEOUT,this); latch.await();# latch等待喚醒 } catch (Exception e) { e.printStackTrace(); } } @Override public void register(String serviceName, String serviceAddress) { try { String registryPath = REGISTRY_PATH; if (zk.exists(registryPath, false) == null) { zk.create(registryPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); #持久化創建/registry node } //創建服務節點(持久節點) String servicePath = registryPath + "/" + serviceName; if (zk.exists(servicePath, false) == null) { zk.create(servicePath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } //創建地址節點 String addressPath = servicePath + "/address-"; # 此處節點是瞬態的節點,當服務斷開zookeeper連接時,節點消失,重新連接時,address- 以序列添加末尾序列值。
這種序列方法可以判斷注冊服務的主被,先注冊的數字小,后注冊的數字大,每次從主上同步數據到被。在服務異常時,節點自動消失,可以探測服務狀態 String addressNode = zk.create(addressPath, serviceAddress.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); } catch (Exception e){ e.printStackTrace(); } } @Override public void process(WatchedEvent watchedEvent) { if (watchedEvent.getState() == Event.KeeperState.SyncConnected) latch.countDown(); }
驗證
啟動zookeeper,啟動以上web服務
java客戶端登錄zookeeper,查詢注冊服務的注冊信息
調用接口查詢zookeeper數據
以上是關於zookeeper的初步探索,可以參考https://github.com/CaesarLinsa/zookeeper_caesar,在version1.0分支中去掉core模塊,添加到service層中,添加對zookeeper操作接口,實現在接口修改zookeeper同時,配置文件發生變更。當然如此需要每個服務的守護進程中存在類似socket通信,在server端發生變化時,在watch中向守護進程中發送相關命令,促使配置變更,服務啟動或者不啟動加載配置。