服务注册:
当provider启动的时候,连接zk集群,便会在zk集群中创建瞬时节点。将自己的url保存到瞬时节点中。
当provider出现宕机,某个服务器的url就会减少,瞬时节点就会自动减少。该服务器重启回复正常,便会重新生成瞬时节点,将该服务器存储的url又重新添加到zk集群中。
服务发现:
当consumer启动的时候,连接zk集群,会获得所有瞬时节点的集合。将其混存到本地的集合中去。
通过负载均衡算法将产生一个可以访问的服务进行访问。当provider发生宕机的情况,consumer会重新进行读取zk集群的列表,重新加载url,将其保存在本地的集合中。
代码实现:
情景: 3个服务器发布三个url地址到zookeeper集群中,当一台服务器关闭(项目),zookeeper便会删除该项目的url(瞬时节点),并重新进行读取。
5.1.1创建zk-rmi-cluseter-provider(jar)项目
5.1.2添加依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjsxt.zk.rmi</groupId>
<artifactId>zk-rmi-cluster-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 添加公共资源依赖 -->
<dependency>
<groupId>com.bjsxt.resources</groupId>
<artifactId>rmi-resources</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- zk的api依赖 -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
</dependency>
</dependencies>
</project>
5.1.3拷贝OrdersServiceImpl实现类
5.1.4创建ProviderApp实现服务发布和注册
package com.bjsxt.app;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import com.bjsxt.service.OrdersService;
import com.bjsxt.service.impl.OrdersServiceImpl;
import org.apache.zookeeper.ZooKeeper;
public class ProviderApp {
//实现线程同步
private CountDownLatch latch=new CountDownLatch(1);
/***
* 建立和zk集群的建立
*/
public ZooKeeper getConnection() {
ZooKeeper zk=null;
try {
zk=new ZooKeeper(Constants.ZK_HOST, Constants.TIME_OUT, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 判断是否和zk集群建立链接
if(event.getState()==Event.KeeperState.SyncConnected) {
latch.countDown(); //唤醒阻塞的线程
}
}
});
//阻塞主线程
latch.await();
}catch(Exception ex) {
ex.printStackTrace();
}
return zk;
}
/***
* 创建瞬时的,顺序节点,同时将自己的url写入到瞬时节点
*/
public void providerRegister(String url) {
try {
ZooKeeper zk=getConnection();
if(zk!=null) {
//创建瞬时,顺序节点
zk.create(Constants.URL, //指定的节点路径,注意自己手动创建/provider
url.getBytes(), //节点中保存的数据
Ids.OPEN_ACL_UNSAFE, //权限
CreateMode.EPHEMERAL_SEQUENTIAL);//节点类型
}
}catch(Exception ex) {
ex.printStackTrace();
}
}
/***
* 实现服务的发布
*/
public void pulisher(Integer port) {
try {
//指定暴露的远程服务的访问端口
LocateRegistry.createRegistry(port);
//创建OrdersServiceImpl实现类
OrdersService remote=new OrdersServiceImpl();
//定义远程访问的url
String name="rmi://localhost:"+port+"/sxt";
//进行给remote对象绑定一个远程访问的地址
Naming.bind(name, remote);
//调用服务的注册方法,完成服务注册
providerRegister(name);
System.out.println("==========发布远程服务===========9999");
}catch(Exception ex) {
ex.printStackTrace();
}
}
/***
* 发布集群服务
*/
public static void main(String[] args) {
ProviderApp app=new ProviderApp();
app.pulisher(9999);
}
}
5.1.5查看发布结果、
5.2.1创建zk-rmi-cluster-consumer(jar)项目
5.2.2添加依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjsxt.zk.rmi.consumer</groupId>
<artifactId>zk-rmi-cluster-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 添加公共资源依赖 -->
<dependency>
<groupId>com.bjsxt.resources</groupId>
<artifactId>rmi-resources</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- zk的api依赖 -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
</dependency>
</dependencies>
</project>
5.2.3拷贝Constants接口
5.2.4创建ConsumerApp启动发现和消费服务
package com.bjsxt.app;
import java.rmi.ConnectException;
import java.rmi.Naming;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import com.bjsxt.pojo.Orders;
import com.bjsxt.service.OrdersService;
/***
* 实现服务的发现和消费
* @author EDZ
*
*/
public class ConsumerApp {
//缓存可用的服务地址列表
private volatile List<String> urls=new ArrayList<>();
//实现线程同步
private CountDownLatch latch=new CountDownLatch(1);
/***
* 建立和zk集群的建立
*/
public ZooKeeper getConnection() {
ZooKeeper zk=null;
try {
zk=new ZooKeeper(Constants.ZK_HOST, Constants.TIME_OUT, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 判断是否和zk集群建立链接
if(event.getState()==Event.KeeperState.SyncConnected) {
latch.countDown(); //唤醒阻塞的线程
}
}
});
//阻塞主线程
latch.await();
}catch(Exception ex) {
ex.printStackTrace();
}
return zk;
}
/***
* 读取zk集群中注册的服务
*/
public void providerFetch() {
try {
ZooKeeper zk=getConnection();
if(zk!=null) {
//读取/provider接下的所有子节点
List<String> children = zk.getChildren(Constants.PROVIDER, new Watcher() {
/***
* 观察/provider节点的子节点是否有变化
*/
@Override
public void process(WatchedEvent event) {
// TODO Auto-generated method stub
if(event.getType()==Event.EventType.NodeChildrenChanged) {
System.out.println("========子节点发生变化========");
providerFetch(); //如果有子节点变化,回调重新读取
}
}
});
//保存读取的服务地址
List<String> path=new ArrayList<>();
//遍历子节点集合children
for(String node:children) {
//System.out.println(node);
//获得node节点中的数据
byte[] data = zk.getData(Constants.PROVIDER+"/"+node, false, null);
//byte[]转化为String
String url=new String(data);
path.add(url);
}
this.urls=path;
}
}catch(Exception ex) {
ex.printStackTrace();
}
}
/***
* 完成服务消费
*/
public void consumer() {
while (true) {
try {
// 产生一个随机数
int index = ThreadLocalRandom.current().nextInt(this.urls.size());
// 远程服务的访问地址
String name = this.urls.get(index);
// 获得远程服务的代理对象
OrdersService remote = (OrdersService) Naming.lookup(name);
// 获得会员订单的集合
List<Orders> list = remote.loadOrdersList(111111);
for (Orders orders : list) {
System.out.println(orders.getId() + "\t"
+ orders.getVip() + "\t" + orders.getOdate() + "\t"
+ orders.getRemark());
}
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 无参数构造方法
*/
public ConsumerApp() {
providerFetch();
}
public static void main(String[] args) {
ConsumerApp app=new ConsumerApp();
app.consumer();
}
}