zookeeper(5)--基于watcher原理实现带注册中心的RPC框架
一、带版本控制的注册中心RPC框架
server端
//注册中心接口
public interface IRegisterCenter { public void register(String serviceName,String serviceAddress);
}
//实现类
package zoorpc.zk; import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode; public class RegisterCenter implements IRegisterCenter { private CuratorFramework curatorFramework; public RegisterCenter() {
curatorFramework = CuratorFrameworkFactory.builder().connectString(ZooConfig.CONNECTION_STR)
.connectionTimeoutMs(4000).retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
curatorFramework.start();
}
@Override
public void register(String serviceName, String serviceAddress) { // 注册相应服务
String Servicepath = ZooConfig.ZK_REGISTER_PATH + "/" + serviceName;
try { //判断服务/registrys/product-service/是否存在,否则创建
if (curatorFramework.checkExists().forPath(Servicepath) == null) {
curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
.forPath(Servicepath,"0".getBytes());
}
//创建服务iP节点
String adressPath = Servicepath+"/"+serviceAddress;
String rsNode = curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
.forPath(adressPath,"0".getBytes());
System.out.println("服务节点创建成功:"+rsNode);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
//常量类
package zoorpc.zk; public class ZooConfig { final static String CONNECTION_STR = "192.168.25.129:2181,192.168.25.130:2181,192.168.25.131:2181";
final static String ZK_REGISTER_PATH = "/registrys";
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RpcAnnotation { /**
* 对外发布的接口地址
* @return
*/
Class<?> value(); //多版本功能扩展
String version() default "";
}
//服务接口
public interface IHelloWorld { public String sayHello(String msg);
}
//服务接口实现类1,不带版本控制
package zoorpc; import anno.RpcAnnotation; @RpcAnnotation(IHelloWorld.class)
public class HelloWorldServiceImpl implements IHelloWorld { @Override
public String sayHello(String msg) {
// TODO Auto-generated method stub
return "HelloWorld,8080"+msg;
} }
//服务接口实现类2,带版本控制
import anno.RpcAnnotation; @RpcAnnotation(value = IHelloWorld.class,version = "2.0")
public class HelloWorldServiceImpl2 implements IHelloWorld { @Override
public String sayHello(String msg) {
// TODO Auto-generated method stub
return "HelloWorld2,8081"+msg;
} }
//服务发布类
package zoorpc; import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import anno.RpcAnnotation;
import zoorpc.zk.IRegisterCenter; public class RpcServer { private static final ExecutorService executorService = Executors.newCachedThreadPool(); private IRegisterCenter registerCenter;//注册中心
private String serviceAddress;//服务发布地址
//存放服务名称和服务对象之间的关系
Map<String,Object> handlerMap = new HashMap<String,Object>(); public RpcServer(IRegisterCenter registerCenter, String serviceAddress) {
this.registerCenter = registerCenter;
this.serviceAddress = serviceAddress;
}
//绑定服务名称和服务对象
public void bind(Object...services){
for(Object service :services ){
RpcAnnotation rpcAnnotation = service.getClass().getAnnotation(RpcAnnotation.class);
String serviceName = rpcAnnotation.value().getName();
//添加版本号控制
String version = rpcAnnotation.version();
if(version!=null && !version.equals("")){
serviceName = serviceName+"-"+version;
}
//添加版本号控制
handlerMap.put(serviceName, service);//绑定接口服务名称及对应的服务
}
}
//发布服务
public void publisher(){
ServerSocket serverSocket = null;
try {
String[] split = serviceAddress.split(":");
serverSocket = new ServerSocket(Integer.parseInt(split[1]));//启动一个服务监听
for(String interfaceName : handlerMap.keySet()){
registerCenter.register(interfaceName, serviceAddress);
System.out.println("服务注册成功:"+interfaceName+"->"+serviceAddress);
}
while(true){
Socket socket = serverSocket.accept();
executorService.execute(new ProcessorHandler(socket,handlerMap));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(serverSocket!=null){
try {
serverSocket.close(); } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} }
}
package zoorpc; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Map; public class ProcessorHandler implements Runnable { private Socket socket;
private Map<String,Object> handlerMap; public ProcessorHandler(Socket socket, Map<String,Object> handlerMap) {
this.socket = socket;
this.handlerMap = handlerMap;
} @Override
public void run() {
// TODO 处理请求
ObjectInputStream objectInputStream =null;
ObjectOutputStream objectOutputStream =null;
try {
objectInputStream = new ObjectInputStream(socket.getInputStream());
RpcRequest request = (RpcRequest) objectInputStream.readObject();
Object result = invoke(request);
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(objectInputStream!=null){
try {
objectInputStream.close();
objectOutputStream.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} private Object invoke(RpcRequest request) throws Exception, IllegalArgumentException, InvocationTargetException{
Object[] args = request.getParameters();
Class<?> [] types = new Class[args.length];
for (int i = 0; i < types.length; i++) {
types[i] = args[i].getClass();
}
//添加版本号控制
String version = request.getVersion();
String serviceName =request.getClassName();
if(version!=null && !version.equals("")){
serviceName =request.getClassName()+"-"+version;
}
//添加版本号控制
//从handlerMap中,根据客户端额请求地址,去拿到响应的服务,通过反射发起调用
//Object service = handlerMap.get(request.getClassName());
Object service = handlerMap.get(serviceName);//添加版本号控制
Method method = service.getClass().getMethod(request.getMethodName(), types);
return method.invoke(service, args);
}
}
//传输类
package zoorpc; import java.io.Serializable;
/**
* 传输对象
* @author admin
*
*/
public class RpcRequest implements Serializable{ private static final long serialVersionUID = 6351477854838485391L;
private String className;
private String methodName;
private Object[] parameters;
private String version; public String getVersion() {
return version;
} public RpcRequest(String className, String methodName, Object[] parameters, String version) {
super();
this.className = className;
this.methodName = methodName;
this.parameters = parameters;
this.version = version;
} public void setVersion(String version) {
this.version = version;
} public RpcRequest(String className, String methodName, Object[] parameters) {
super();
this.className = className;
this.methodName = methodName;
this.parameters = parameters;
} public RpcRequest() {
super();
// TODO Auto-generated constructor stub
} public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getParameters() {
return parameters;
}
public void setParameters(Object[] parameters) {
this.parameters = parameters;
} }
//发布服务
package zoorpc; import java.io.IOException; import zoorpc.zk.IRegisterCenter;
import zoorpc.zk.RegisterCenter; public class ServerDemo { public static void main(String[] args) throws IOException {
IHelloWorld service = new HelloWorldServiceImpl();
IHelloWorld service2 = new HelloWorldServiceImpl2();
IRegisterCenter registerCenter = new RegisterCenter();
RpcServer server = new RpcServer(registerCenter,"127.0.0.1:8080");
server.bind(service,service2);
server.publisher();
System.in.read();
}
}
客户端
package zoorpc.zk; public interface IDiscovery { /**
* 根据请求的服务地址,获取到服务的调用地址
* @param serviceName
* @return
*/
public String Discovery(String serviceName);
}
package zoorpc.zk; import java.util.ArrayList;
import java.util.List; import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry; import zoorpc.loadbalance.ILoadBalance;
import zoorpc.loadbalance.RandomLoadBalance; public class Discovery implements IDiscovery { private CuratorFramework curatorFramework; List<String> repos = new ArrayList<>();
private String adresses;
public Discovery(String adresses) {
this.adresses = adresses;
curatorFramework = CuratorFrameworkFactory.builder().connectString(adresses)
.connectionTimeoutMs(4000).retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
curatorFramework.start();
}
@Override
public String Discovery(String serviceName) {
String path = ZooConfig.ZK_REGISTER_PATH + "/" + serviceName;
ILoadBalance randomLoadBalance = null;
try {
repos = curatorFramework.getChildren().forPath(path);
//动态发现节点的变化
registerWatcher(path);
//发现多个服务,做负载均衡
randomLoadBalance = new RandomLoadBalance(); } catch (Exception e) {
e.printStackTrace();
} return randomLoadBalance.selectHost(repos);//返回调用的服务地址
} private void registerWatcher(final String path) throws Exception{
PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, path, true);
PathChildrenCacheListener pathChildrenCacheListener = new PathChildrenCacheListener() { @Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
repos = curatorFramework.getChildren().forPath(path);
}
};
pathChildrenCache.getListenable().addListener(pathChildrenCacheListener);
pathChildrenCache.start();
}
}
package zoorpc.zk; public class ZooConfig { public final static String CONNECTION_STR = "192.168.25.129:2181,192.168.25.130:2181,192.168.25.131:2181";
public final static String ZK_REGISTER_PATH = "/registrys";
}
package zoorpc; public interface IHelloWorld { public String sayHello(String msg);
}
package zoorpc; import java.io.Serializable;
/**
* 传输对象
* @author admin
*
*/
public class RpcRequest implements Serializable{ private static final long serialVersionUID = 6351477854838485391L;
private String className;
private String methodName;
private Object[] parameters;
private String version; public String getVersion() {
return version;
} public void setVersion(String version) {
this.version = version;
} public RpcRequest(String className, String methodName, Object[] parameters) {
super();
this.className = className;
this.methodName = methodName;
this.parameters = parameters;
} public RpcRequest() {
super();
// TODO Auto-generated constructor stub
} public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getParameters() {
return parameters;
}
public void setParameters(Object[] parameters) {
this.parameters = parameters;
} }
package zoorpc; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import zoorpc.zk.IDiscovery; public class RpcClientProxy { private IDiscovery discovery; public RpcClientProxy(IDiscovery discovery) {
this.discovery = discovery;
} public <T> T clientProxy(final Class<T> interfaceCls,String version){ return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(),
new Class[] {interfaceCls},
new RemoteInvocationHandler(version,discovery)); }
}
package zoorpc; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.Socket; import zoorpc.zk.IDiscovery; public class RemoteInvocationHandler implements InvocationHandler { private String version;//添加版本号控制
private IDiscovery discovery; public RemoteInvocationHandler(String version,IDiscovery discovery) {
this.discovery = discovery;
this.version = version;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
RpcRequest request = new RpcRequest();
request.setClassName(method.getDeclaringClass().getName());
request.setMethodName(method.getName());
request.setParameters(args);
request.setVersion(version);
String serviceAddress = discovery.Discovery(request.getClassName());
TcpTransport trans = new TcpTransport(serviceAddress);
return trans.send(request);
} }
package zoorpc; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket; public class TcpTransport { private String serviceAddress; public TcpTransport(String serviceAddress) {
super();
this.serviceAddress = serviceAddress;
} Socket newSocket(){
System.out.println("创建一个连接");
Socket socket = null;
try {
String[] split = serviceAddress.split(":");
socket = new Socket(split[0],Integer.parseInt(split[1]));
return socket;
} catch (Exception e) {
// TODO: handle exception
throw new RuntimeException("连接建立失败!");
}
} public Object send(RpcRequest request){
Socket socket = null;
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
try {
socket = newSocket(); objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(request);
objectOutputStream.flush(); objectInputStream = new ObjectInputStream(socket.getInputStream());
Object readObject = objectInputStream.readObject();
return readObject;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
throw new RuntimeException("连接建立失败!");
}finally {
if(socket!=null){
try {
socket.close();
objectOutputStream.close();
objectInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} }
package zoorpc.loadbalance; import java.util.List; public interface ILoadBalance { public String selectHost(List<String> repos); }
package zoorpc.loadbalance; import java.util.List; public abstract class LoadBalance implements ILoadBalance{ @Override
public String selectHost(List<String> repos) {
if(repos.size()<){
return null;
}else if(repos.size() ==){
return repos.get();
}else{
return doSelect(repos);
}
} protected abstract String doSelect(List<String> repos);
}
package zoorpc.loadbalance; import java.util.List;
import java.util.Random; public class RandomLoadBalance extends LoadBalance { @Override
protected String doSelect(List<String> repos) {
int len = repos.size();
Random random = new Random();
return repos.get(random.nextInt(len)); } }
package zoorpc; import zoorpc.zk.Discovery;
import zoorpc.zk.IDiscovery;
import zoorpc.zk.ZooConfig; public class ClientDemo {
public static void main(String[] args) {
IDiscovery discovery = new Discovery(ZooConfig.CONNECTION_STR);
RpcClientProxy rpcClientProxy = new RpcClientProxy(discovery);
//IHelloWorld hello = rpcClientProxy.clientProxy(IHelloWorld.class,"");结果:HelloWorld,8080lf
IHelloWorld hello = rpcClientProxy.clientProxy(IHelloWorld.class,"2.0");结果:HelloWorld2,8081lf
System.out.println(hello.sayHello("lf"));
}
}
二、模拟集群
新增发布类:
package zoorpc; import java.io.IOException; import zoorpc.zk.IRegisterCenter;
import zoorpc.zk.RegisterCenter; public class LBServerDemo1 {
//模拟集群
public static void main(String[] args) throws IOException {
IHelloWorld service = new HelloWorldServiceImpl();
IRegisterCenter registerCenter = new RegisterCenter();
RpcServer server = new RpcServer(registerCenter,"127.0.0.1:8080");
server.bind(service);
server.publisher();
System.in.read();
}
}
package zoorpc; import java.io.IOException; import zoorpc.zk.IRegisterCenter;
import zoorpc.zk.RegisterCenter; public class LBServerDemo2 {
//模拟集群
public static void main(String[] args) throws IOException {
IHelloWorld service = new HelloWorldServiceImpl2();
IRegisterCenter registerCenter = new RegisterCenter();
RpcServer server = new RpcServer(registerCenter,"127.0.0.1:8081");
server.bind(service);
server.publisher();
System.in.read();
}
}
修改示例2类的注解
package zoorpc; import anno.RpcAnnotation; //@RpcAnnotation(value = IHelloWorld.class,version = "2.0")
@RpcAnnotation(value = IHelloWorld.class)
public class HelloWorldServiceImpl2 implements IHelloWorld { @Override
public String sayHello(String msg) {
// TODO Auto-generated method stub
return "HelloWorld2,8081"+msg;
} }
运行发布类1,2
linux 下查看节点显示:
[zk: localhost:2181(CONNECTED) 13] ls /registrys/zoorpc.IHelloWorld
[127.0.0.1:8081, 127.0.0.1:8080]
[zk: localhost:2181(CONNECTED) 14]
客户端
package zoorpc; import zoorpc.zk.Discovery;
import zoorpc.zk.IDiscovery;
import zoorpc.zk.ZooConfig; public class LBClientDemo {
public static void main(String[] args) throws InterruptedException {
IDiscovery discovery = new Discovery(ZooConfig.CONNECTION_STR);
RpcClientProxy rpcClientProxy = new RpcClientProxy(discovery);
for (int i = ; i < ; i++) {
IHelloWorld hello = rpcClientProxy.clientProxy(IHelloWorld.class,null);
System.out.println(hello.sayHello("lf"));
Thread.sleep();
}
}
}
运行结果:
创建一个连接
HelloWorld,8080lf
创建一个连接
HelloWorld,8080lf
创建一个连接
HelloWorld2,8081lf
创建一个连接
HelloWorld2,8081lf
创建一个连接
HelloWorld2,8081lf
创建一个连接
HelloWorld2,8081lf
创建一个连接
HelloWorld2,8081lf
创建一个连接
HelloWorld,8080lf
创建一个连接
HelloWorld,8080lf
创建一个连接
HelloWorld2,8081lf
实现原理图:
四、集群扩容
一、停机扩容,修改配置
二、逐台扩容,一台台重启
zookeeper(5)--基于watcher原理实现带注册中心的RPC框架的更多相关文章
- 手写实现RPC框架(不带注册中心和带注册中心两种)
实现自己的RPC框架如果不需要自定义协议的话那就要基于Socket+序列化. ProcessorHandler:主要是用来处理客户端的请求. package dgb.nospring.myrpc; i ...
- [年薪60W分水岭]基于Netty手写Apache Dubbo(带注册中心和注解)
阅读这篇文章之前,建议先阅读和这篇文章关联的内容. 1. 详细剖析分布式微服务架构下网络通信的底层实现原理(图解) 2. (年薪60W的技巧)工作了5年,你真的理解Netty以及为什么要用吗?(深度干 ...
- 基于Netty4手把手实现一个带注册中心和注解的Dubbo框架
阅读这篇文章之前,建议先阅读和这篇文章关联的内容. 1. 详细剖析分布式微服务架构下网络通信的底层实现原理(图解) 2. (年薪60W的技巧)工作了5年,你真的理解Netty以及为什么要用吗?(深度干 ...
- RPC与Zookeeper注册中心的简单实现
连接上文:https://www.cnblogs.com/wuzhenzhao/p/9962250.html RPC框架的简单实现,基于这个小程序,在我学习完Zookeeper之后如何将注册中心与RP ...
- 简单RPC框架-基于Consul的服务注册与发现
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- 如果有人问你 Dubbo 中注册中心工作原理,就把这篇文章给他
注册中心作用 开篇首先想思考一个问题,没有注册中心 Dubbo 还能玩下去吗? 当然可以,只要知道服务提供者地址相关信息,消费者配置之后就可以调用.如果只有几个服务,这么玩当然没问题.但是生产服务动辄 ...
- Spring Cloud 系列之 ZooKeeper 注册中心
什么是注册中心 服务注册中心是服务实现服务化管理的核心组件,类似于目录服务的作用,主要用来存储服务信息,譬如提供者 url 串.路由信息等.服务注册中心是微服务架构中最基础的设施之一. 注册中心可以说 ...
- zookeeper、consul 实现注册中心
1.Zookeeper 分布式协调工具,可以实现注册中心 所有实现方式基本一致,只需要先开启zookeeper的服务端,然后再打开客户端jar包即可. Zookeeper一开始连接失败,后面又可以了, ...
- dubbo学习(五)注册中心zookeeper
初识zookeeper 下载地址:https://archive.apache.org/dist/zookeeper/ 详细的ZooKeeper教程戳这里~ PS: 建议目前选择3.4的稳定版本进行使 ...
随机推荐
- https 不检验证书
System.Net.ServicePointManager.ServerCertificateValidationCallback += (s, cert, chain, sslPolicyErro ...
- Java 可执行jar的manifest编写
Eclipse:形式, 选中项目右键 命令行形式: 1.编写Java类 2.命令行指定到项目/src文件夹,编译 3.编写manifest文件 4.目录重新定位到bin/classes编译文件目录下, ...
- Linux bash笔记
关于bash脚本,一般开头都加#!/bin/bash,表示以bash来作为脚本解释器:如果不加的话,就会默认当前用户登陆的shell为脚本解释器(很多情况下为sh,sh与bash不同,有可能导致脚本无 ...
- nodeJS安装及npm设置淘宝镜像
node.js安装 下载node.js安装包:https://nodejs.org/en/download/,下载相应版本的node.js. 需注意,在window中,node的安装目录中,最好不要有 ...
- 其他类想使用unittest的断言方法,就import unittest的框架,继承他,使用他里面的方法
在断言层 也可以同样用这个方法
- 补充appium -api
//锁屏 driver.lockScreen(2); //判断是否锁屏 driver.isLocked(); //截屏并保存至本地 File screen = driver.getScreenshot ...
- ElasticSearch 5.0.0 安装部署常见错误或问题
1.ERROR: bootstrap checks failed [1]: max file descriptors [65535] for elasticsearch process is too ...
- eKingCloud 从 OpenStack 到 OpenInfra 演进之路
本内容首发于 2016/06/21 北京 OpenInfra 大会上本人的演讲 发文章要求至少150个字,那就把最后一页说明一下吧. 我前面介绍了我们的5大产品,包括企业的私有云架构和实践,包括企业数 ...
- [转][Centos]一、了解关机
来自:https://blog.csdn.net/ronmy/article/details/79117390 Linux centos关机与重启命令详解与实战 Linux centos重启命令: 1 ...
- Ring0创建事件Ring3设置事件
同步事件(synchronizationEvent)当事件对象为激发时,如遇到KeWaitForXX等内核函数,事件对象则自动变回未激发态通知事件(NotificationEvent)当事件对象为激发 ...