RPC是什么?远程过程调用,过程就是业务处理、计算任务,像调用本地方法一样调用远程的过程。

  RMI和RPC的区别是什么?RMI是远程方法调用,是oop领域中RPC的一种实现,我们熟悉的restfull和webservice都是RPC,仅仅消息的组织方式和消息协议不同。

  RPC调用过程 :

  1、客户端处理过程中调用client sub(像调用本地方法一样),传递参数
  2、client sub将参数编组为消息,然后通过系统调用想服务端发送消息
  3、客户端本地操作系统将消息发送给服务端
  4、服务端操作系统将收到的消息包传给server sub,
  5、server sub解组消息为参数
  6、server sub 调用本地服务,执行结果以反方向相同步骤返回给客户端

  RPC协议 消息由哪些部分构成及消息的表示形式就构成了消息协议,RPC调用过程中采用的消息协议称为RPC协议,可以使用通用的协议(http、https),也可以自定义协议

  RPC框架 封装好参数编组、消息解组、底层通信的RPC程序开发框架,可以在其基础上只需专注于过程代码编写,例如常用的dubbo和springcloud。

  实现RPC的要点有:消息编组解组、服务注册发现和底层通信,本次基于JDK序列化编组解组消息、zookeeper服务注册发现及netty底层通信来实现自己的RPC框架

  消息协议

package com.example.demo.protocol;

/**
* @author hehang on 2019-09-17
* @description 请求
*/
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map; public class Request implements Serializable { private static final long serialVersionUID = -5200571424236772650L; private String serviceName; private String method; private Map<String, String> headers = new HashMap<String, String>(); private Class<?>[] prameterTypes; private Object[] parameters; public String getServiceName() {
return serviceName;
} public void setServiceName(String serviceName) {
this.serviceName = serviceName;
} public String getMethod() {
return method;
} public void setMethod(String method) {
this.method = method;
} public Map<String, String> getHeaders() {
return headers;
} public void setHeaders(Map<String, String> headers) {
this.headers = headers;
} public Class<?>[] getPrameterTypes() {
return prameterTypes;
} public void setPrameterTypes(Class<?>[] prameterTypes) {
this.prameterTypes = prameterTypes;
} public void setParameters(Object[] prameters) {
this.parameters = prameters;
} public String getHeader(String name) {
return this.headers == null ? null : this.headers.get(name);
} public Object[] getParameters() {
return this.parameters;
} }
package com.example.demo.protocol;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map; /**
* @author hehang on 2019-09-17
* @description 响应
*/
public class Response implements Serializable { private static final long serialVersionUID = -4317845782629589997L; private Status status; private Map<String, String> headers = new HashMap<String, String>(); private Object returnValue; private Exception exception; public Response() {
} ; public Response(Status status) {
this.status = status;
} public void setStatus(Status status) {
this.status = status;
} public void setHeaders(Map<String, String> headers) {
this.headers = headers;
} public void setReturnValue(Object returnValue) {
this.returnValue = returnValue;
} public void setException(Exception exception) {
this.exception = exception;
} public Status getStatus() {
return status;
} public Map<String, String> getHeaders() {
return headers;
} public Object getReturnValue() {
return returnValue;
} public Exception getException() {
return exception;
} public String getHeader(String name) {
return this.headers == null ? null : this.headers.get(name);
} public void setHaader(String name, String value) {
this.headers.put(name, value); } }
package com.example.demo.protocol;

public enum Status {
SUCCESS(200, "SUCCESS"), ERROR(500, "ERROR"), NOT_FOUND(404, "NOT FOUND"); private int code; private String message; private Status(int code, String message) {
this.code = code;
this.message = message;
} public int getCode() {
return code;
} public String getMessage() {
return message;
}
}
package com.example.demo.protocol;

public interface MessageProtocol {

    byte[] marshallingRequest(Request request) throws Exception;
Request unmarshallingRequest(byte[] bytes) throws Exception;
byte[] marshallingResponse(Response response) throws Exception;
Response unmarshallingReposne(byte[] bytes)throws Exception; }
package com.example.demo.protocol;

import java.io.*;

/**
* @author hehang on 2019-09-17
* @description 基于jdk序列化的消息协议,我们也可以基于FastJSON序列化实现消息协议,甚至复杂的http协议等
* jdk序列化时,被序列化的对象必须实现序列化接口,其内的属性也必须实现
*/
public class JdkSerializeMessageProtocal implements MessageProtocol { public byte[] marshallingRequest(Request request) throws Exception {
return serialize(request);
} public Request unmarshallingRequest(byte[] bytes) throws Exception {
return (Request) unserialize(bytes);
} public byte[] marshallingResponse(Response response) throws Exception {
return serialize(response);
} public Response unmarshallingReposne(byte[] bytes) throws Exception{
return (Response) unserialize(bytes);
} private byte[] serialize(Object obj) throws Exception{
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
} private Object unserialize(byte[] bytes) throws Exception{
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
return objectInputStream.readObject();
}
}

  服务发现

package com.example.demo.common;

import org.I0Itec.zkclient.exception.ZkMarshallingError;
import org.I0Itec.zkclient.serialize.ZkSerializer; import java.io.UnsupportedEncodingException; /**
* @author hehang on 2019-09-17
* @description zk序列化
*/
public class MyZkSerializer implements ZkSerializer {
String charset = "UTF-8"; public Object deserialize(byte[] bytes) throws ZkMarshallingError {
try {
return new String(bytes, charset);
} catch (UnsupportedEncodingException e) {
throw new ZkMarshallingError(e);
}
} public byte[] serialize(Object obj) throws ZkMarshallingError {
try {
return String.valueOf(obj).getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new ZkMarshallingError(e);
}
}
}
package com.example.demo.discovery;

/**
* @author hehang on 2019-09-17
* @description 服务信息
*/
public class ServiceInfo { private String name;
private String protocol;
private String address; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getProtocol() {
return protocol;
} public void setProtocol(String protocol) {
this.protocol = protocol;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
}
}
package com.example.demo.discovery;

import java.util.List;

public interface ServiceInfoDiscoverer {

    List<ServiceInfo> getServerInfos(String name);
}
package com.example.demo.discovery;

import com.alibaba.fastjson.JSON;
import com.example.demo.common.MyZkSerializer;
import com.example.demo.utils.PropertiesUtil;
import org.I0Itec.zkclient.ZkClient; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List; /**
* @author hehang on 2019-09-17
* @description zk服务发现
*/
public class ZkServiceInfoDiscoverer implements ServiceInfoDiscoverer {
private ZkClient zkClient; private String rootPath = "/rpc"; public ZkServiceInfoDiscoverer(){
String zkAddress = PropertiesUtil.getValue("zk.address");
zkClient = new ZkClient(zkAddress);
zkClient.setZkSerializer(new MyZkSerializer());
} public List<ServiceInfo> getServerInfos(String name) {
String path = rootPath +"/"+ name +"/service";
List<String> children = zkClient.getChildren(path);
List<ServiceInfo> serviceInfos = new ArrayList<ServiceInfo>();
for (String child : children) {
try {
String decode = URLDecoder.decode(child,"UTF-8");
ServiceInfo serviceInfo = JSON.parseObject(decode,ServiceInfo.class);
serviceInfos.add(serviceInfo);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} return serviceInfos;
}
}

  网络通信客户端

package com.example.demo.client.net;

import com.example.demo.discovery.ServiceInfo;

public interface NetClient {

    byte[] sentRequest(byte[] bytes, ServiceInfo serviceInfo) throws Throwable;
}
package com.example.demo.client.net;

import com.example.demo.discovery.ServiceInfo;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.concurrent.CountDownLatch; /**
* @author hehang on 2019-09-17
* @description netty实现底层通信,也可以利用bio、原生nio等实现
*/
public class NettyNetClient implements NetClient {
private static Logger logger = LoggerFactory.getLogger(NettyNetClient.class); public byte[] sentRequest(final byte[] bytes, ServiceInfo serviceInfo) throws Throwable {
String[] addreddInfoArray = serviceInfo.getAddress().split(":");
final SendHandler sendHandler = new SendHandler(bytes);
byte[] respData = null;
// 配置客户端
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(sendHandler);
}
}); // 启动客户端连接
b.connect(addreddInfoArray[0], Integer.valueOf(addreddInfoArray[1])).sync();
respData = (byte[]) sendHandler.responseData();
logger.info("收到响应消息: " + respData); } finally {
// 释放线程组资源
group.shutdownGracefully();
} return respData;
} private class SendHandler extends ChannelInboundHandlerAdapter { private CountDownLatch cdl = null;
private Object responseMsg = null;
private byte[] data; public SendHandler(byte[] bytes){
cdl = new CountDownLatch(1);
data = bytes;
} @Override
public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
logger.info("连接服务端成功");
ByteBuf reqBuf = Unpooled.buffer(data.length);
reqBuf.writeBytes(data);
logger.info("客户端发送消息:" + reqBuf);
channelHandlerContext.writeAndFlush(reqBuf); } public Object responseData(){
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return responseMsg;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info("client sub 读取到响应信息:" + msg);
ByteBuf byteBuf = (ByteBuf) msg;
byte[] resp = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(resp);
responseMsg = resp;
cdl.countDown();
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
logger.error("发生异常",cause);
ctx.close();
} }
}

  JDK动态代理生成代理类

package com.example.demo.client;

import com.example.demo.client.net.NetClient;
import com.example.demo.discovery.ServiceInfo;
import com.example.demo.discovery.ServiceInfoDiscoverer;
import com.example.demo.protocol.MessageProtocol;
import com.example.demo.protocol.Request;
import com.example.demo.protocol.Response;
import org.omg.CORBA.OBJ_ADAPTER; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random; /**
* @author hehang on 2019-09-17
* @description 代理工厂
*/
public class ClientSubProxyFactory { private ServiceInfoDiscoverer serviceInfoDiscoverer; private Map<String, MessageProtocol> supportMessageprotocol ; private NetClient netClient; private Map<Class<?>, Object> objectCahce = new HashMap<Class<?>, Object>(); public <T> T getProxy(Class<?> interf){
T object = (T) this.objectCahce.get(interf);
if(object==null){
object = (T) Proxy.newProxyInstance(interf.getClassLoader(), new Class<?>[]{interf}, new ClientStubInvocationHandler(interf));
this.objectCahce.put(interf,object);
}
return object;
} public ServiceInfoDiscoverer getServiceInfoDiscoverer() {
return serviceInfoDiscoverer;
} public void setServiceInfoDiscoverer(ServiceInfoDiscoverer serviceInfoDiscoverer) {
this.serviceInfoDiscoverer = serviceInfoDiscoverer;
} public Map<String, MessageProtocol> getSupportMessageprotocol() {
return supportMessageprotocol;
} public void setSupportMessageprotocol(Map<String, MessageProtocol> supportMessageprotocol) {
this.supportMessageprotocol = supportMessageprotocol;
} public NetClient getNetClient() {
return netClient;
} public void setNetClient(NetClient netClient) {
this.netClient = netClient;
} public Map<Class<?>, Object> getObjectCahce() {
return objectCahce;
} public void setObjectCahce(Map<Class<?>, Object> objectCahce) {
this.objectCahce = objectCahce;
} private class ClientStubInvocationHandler implements InvocationHandler{ private Class<?> interf; private Random random = new Random(); public ClientStubInvocationHandler(Class<?> interf){
super();
this.interf = interf;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("toString")) {
return proxy.getClass().toString();
} if (method.getName().equals("hashCode")) {
return 0;
}
//得到服务信息
String serviceName = interf.getName();
List<ServiceInfo> serviceInfos = serviceInfoDiscoverer.getServerInfos(serviceName);
if(serviceInfos==null && serviceInfos.size()==0){
throw new Exception("服务不存在");
}
//随机选择一个服务
ServiceInfo serviceInfo = serviceInfos.get(random.nextInt(serviceInfos.size()));
//构造请求信息
Request request = new Request();
request.setServiceName(serviceName);
request.setMethod(method.getName());
request.setPrameterTypes(method.getParameterTypes());
request.setParameters(args);
//消息编组
MessageProtocol messageProtocol = supportMessageprotocol.get(serviceInfo.getProtocol());
byte[] bytes = messageProtocol.marshallingRequest(request);
//发送请求
byte[] rpsBytes = netClient.sentRequest(bytes, serviceInfo);
//消息解组
Response response = messageProtocol.unmarshallingReposne(rpsBytes); if(response.getException()!=null){
throw response.getException();
}
return response.getReturnValue();
}
}
}

  服务注册

package com.example.demo.register;

/**
* @author hehang on 2019-09-17
* @description 服务object
*/
public class ServiceObject { private String name; private Class<?> interf; private Object obj; public ServiceObject(String name, Class<?> interf, Object obj) {
super();
this.name = name;
this.interf = interf;
this.obj = obj;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Class<?> getInterf() {
return interf;
} public void setInterf(Class<?> interf) {
this.interf = interf;
} public Object getObj() {
return obj;
} public void setObj(Object obj) {
this.obj = obj;
} }
package com.example.demo.register;

import java.net.UnknownHostException;

public interface ServiceRegister {

    void register (ServiceObject serviceObject,String protocol,int port) throws Exception;

    ServiceObject getServiceObject(String name);
}
package com.example.demo.register;

import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map; /**
* @author hehang on 2019-09-17
* @description
*/
public class DefaultServiceRegister implements ServiceRegister { private Map<String,ServiceObject> map = new HashMap<String, ServiceObject>();
public void register(ServiceObject serviceObject, String protocol, int port) throws Exception {
if(serviceObject==null){
throw new IllegalArgumentException("参数不能为空");
}
map.put(serviceObject.getName(),serviceObject);
} public ServiceObject getServiceObject(String name) {
return map.get(name);
}
}
package com.example.demo.register;

import com.alibaba.fastjson.JSON;
import com.example.demo.common.MyZkSerializer;
import com.example.demo.discovery.ServiceInfo;
import com.example.demo.utils.PropertiesUtil;
import org.I0Itec.zkclient.ZkClient; import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException; /**
* @author hehang on 2019-09-17
* @description
*/
public class ZookeeperExportServiceRegister extends DefaultServiceRegister implements ServiceRegister { private ZkClient zkClient; private String rootPath ="/rpc"; public ZookeeperExportServiceRegister(){
String addr = PropertiesUtil.getValue("zk.address");
zkClient = new ZkClient(addr);
zkClient.setZkSerializer(new MyZkSerializer()); } @Override
public void register(ServiceObject serviceObject, String protocol, int port) throws Exception {
super.register(serviceObject, protocol, port);
ServiceInfo serviceInfo = new ServiceInfo();
String hostIp = InetAddress.getLocalHost().getHostAddress();
String address = hostIp + ":" + port;
serviceInfo.setAddress(address);
serviceInfo.setName(serviceObject.getInterf().getName());
serviceInfo.setProtocol(protocol);
exportService(serviceInfo); } private void exportService(ServiceInfo serviceInfo ){
String serviceName = serviceInfo.getName();
String uri = JSON.toJSONString(serviceInfo);
try {
uri = URLEncoder.encode(uri,"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String servicePath = rootPath + "/" + serviceName + "/service";
if(!zkClient.exists(servicePath)){
zkClient.createPersistent(servicePath,true);
}
String uriPath = servicePath + "/" + uri;
if(zkClient.exists(uriPath)){
zkClient.delete(uriPath);
}
zkClient.createEphemeral(uriPath);
}
}

  网络通信服务器

package com.example.demo.server;

import com.example.demo.protocol.MessageProtocol;
import com.example.demo.protocol.Request;
import com.example.demo.protocol.Response;
import com.example.demo.protocol.Status;
import com.example.demo.register.ServiceObject;
import com.example.demo.register.ServiceRegister; import java.lang.reflect.Method; /**
* @author hehang on 2019-09-17
* @description 请求处理类
*/
public class RequestHandler { private MessageProtocol messageProtocol; private ServiceRegister serviceRegister; public RequestHandler(MessageProtocol protocol, ServiceRegister serviceRegister) {
super();
this.messageProtocol = protocol;
this.serviceRegister = serviceRegister;
} public byte[] handlerRequest(byte[] data) throws Exception {
//解组消息
Request request = messageProtocol.unmarshallingRequest(data);
//获取处理对象
ServiceObject serviceObject = serviceRegister.getServiceObject(request.getServiceName());
Response rsp = null;
if (serviceObject == null) {
rsp = new Response(Status.NOT_FOUND);
} else {
//利用反射调用
try {
Method method = serviceObject.getInterf().getMethod(request.getMethod(), request.getPrameterTypes());
Object obj = method.invoke(serviceObject.getObj(), request.getParameters());
rsp = new Response(Status.SUCCESS);
rsp.setReturnValue(obj);
} catch (Exception e) {
rsp = new Response(Status.ERROR);
rsp.setException(e);
} } //编组消息
return messageProtocol.marshallingResponse(rsp); } public MessageProtocol getMessageProtocol() {
return messageProtocol;
} public void setMessageProtocol(MessageProtocol messageProtocol) {
this.messageProtocol = messageProtocol;
} public ServiceRegister getServiceRegister() {
return serviceRegister;
} public void setServiceRegister(ServiceRegister serviceRegister) {
this.serviceRegister = serviceRegister;
}
}
package com.example.demo.server;

public abstract class RpcServer {

    protected int port;

    protected String protocol;

    protected RequestHandler handler;

    public RpcServer(int port, String protocol, RequestHandler handler) {
super();
this.port = port;
this.protocol = protocol;
this.handler = handler;
}
/**
* 开启服务
*/
public abstract void start(); /**
* 停止服务
*/
public abstract void stop(); public int getPort() {
return port;
} public void setPort(int port) {
this.port = port;
} public String getProtocol() {
return protocol;
} public void setProtocol(String protocol) {
this.protocol = protocol;
} public RequestHandler getHandler() {
return handler;
} public void setHandler(RequestHandler handler) {
this.handler = handler;
} }
package com.example.demo.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* @author hehang on 2019-09-17
* @description
*/
public class NettyRpcServer extends RpcServer { private Channel channel; public NettyRpcServer(int port, String protocol, RequestHandler handler) {
super(port, protocol, handler);
} private static Logger logger = LoggerFactory.getLogger(NettyRpcServer.class); @Override
public void start() {
EventLoopGroup bossLoopGroup = new NioEventLoopGroup();
EventLoopGroup workLoopGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossLoopGroup,workLoopGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,100).handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline p = socketChannel.pipeline();
p.addLast(new ChannelRequestHandler());
}
});
try {
//启动服务
ChannelFuture future = serverBootstrap.bind(port).sync();
logger.info("绑定成功");
channel = future.channel();
// 等待服务通道关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 释放线程组资源
bossLoopGroup.shutdownGracefully();
workLoopGroup.shutdownGracefully(); } } @Override
public void stop() {
this.channel.close();
} private class ChannelRequestHandler extends ChannelInboundHandlerAdapter{ @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info("激活");
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info("服务端收到消息:" + msg);
ByteBuf byteBuf = (ByteBuf) msg;
byte[] req = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(req);
byte[] res = handler.handlerRequest(req);
logger.info("服务端对消息:" + msg +"响应");
ByteBuf rpsBuf = Unpooled.buffer(res.length);
rpsBuf.writeBytes(res);
ctx.write(rpsBuf);
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
logger.error("发生异常:" + cause.getMessage());
ctx.close();
} }
}

  测试代码

package com.example.demo.main;

/**
* @author hehang on 2019-09-17
* @description demo
*/
public interface DemoService { String sayHello(String param);
}
package com.example.demo.main;

import com.example.demo.client.ClientSubProxyFactory;
import com.example.demo.client.net.NettyNetClient;
import com.example.demo.discovery.ZkServiceInfoDiscoverer;
import com.example.demo.protocol.JdkSerializeMessageProtocal;
import com.example.demo.protocol.MessageProtocol; import java.util.HashMap;
import java.util.Map; /**
* @author hehang on 2019-09-17
* @description 客户端测试类
*/
public class Consume { public static void main(String[] args) {
ClientSubProxyFactory clientSubProxyFactory = new ClientSubProxyFactory();
clientSubProxyFactory.setServiceInfoDiscoverer(new ZkServiceInfoDiscoverer());
Map<String, MessageProtocol> messageProtocolMap = new HashMap<String, MessageProtocol>();
messageProtocolMap.put("jdks",new JdkSerializeMessageProtocal());
clientSubProxyFactory.setSupportMessageprotocol(messageProtocolMap);
clientSubProxyFactory.setNetClient(new NettyNetClient());
DemoService demoService = clientSubProxyFactory.getProxy(DemoService.class);
String result = demoService.sayHello("hello");
System.out.println(result); }
}
package com.example.demo.main.impl;

import com.example.demo.main.DemoService;

/**
* @author hehang on 2019-09-17
* @description
*/
public class DemoServiceImpl implements DemoService {
public String sayHello(String param) {
return param + "word";
}
}
package com.example.demo.main;

import com.example.demo.main.impl.DemoServiceImpl;
import com.example.demo.protocol.JdkSerializeMessageProtocal;
import com.example.demo.register.ServiceObject;
import com.example.demo.register.ServiceRegister;
import com.example.demo.register.ZookeeperExportServiceRegister;
import com.example.demo.server.NettyRpcServer;
import com.example.demo.server.RequestHandler;
import com.example.demo.server.RpcServer;
import com.example.demo.utils.PropertiesUtil; /**
* @author hehang on 2019-09-17
* @description
*/
public class Provider { public static void main(String[] args) throws Exception { int port = Integer.parseInt(PropertiesUtil.getValue("rpc.port"));
String protocol = PropertiesUtil.getValue("rpc.protocol");
ServiceRegister serviceRegister = new ZookeeperExportServiceRegister();
DemoService demoService = new DemoServiceImpl();
ServiceObject serviceObject = new ServiceObject(DemoService.class.getName(), DemoService.class, demoService);
serviceRegister.register(serviceObject, protocol, port);
RequestHandler requestHandler = new RequestHandler(new JdkSerializeMessageProtocal(), serviceRegister);
RpcServer rpcServer = new NettyRpcServer(port, protocol, requestHandler);
rpcServer.start();
System.in.read();
rpcServer.stop(); }
}

  配置文件读取工具类及配置

package com.example.demo.utils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties; /**
* @author hehang on 2019-09-17
* @description 读取配置文件
*/
public class PropertiesUtil { private static Properties properties;
static{ properties = new Properties();
try {
properties.load(PropertiesUtil.class.getClassLoader().getResourceAsStream("app.properties"));
} catch (IOException e) {
e.printStackTrace();
}
} public static String getValue(String key){
return (String) properties.get(key);
} }
zk.address=127.0.0.1:2181
rpc.port=15002
rpc.protocol=jdks
log4j.rootLogger=info,stdout
log4j.threshhold=ALL
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %T %-5p %c{2} (%F:%M(%L)) - %m%n

  相关依赖

<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.32.Final</version>
</dependency>
<!-- SLF4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
</dependencies>

手写RPC框架(netty+zookeeper)的更多相关文章

  1. 手写RPC框架(六)整合Netty

    手写RPC框架(六)整合Netty Netty简介: Netty是一个基于NIO的,提供异步,事件驱动的网络应用工具,具有高性能高可靠性等特点. 使用传统的Socket来进行网络通信,服务端每一个连接 ...

  2. 手写RPC框架指北另送贴心注释代码一套

    Angular8正式发布了,Java13再过几个月也要发布了,技术迭代这么快,框架的复杂度越来越大,但是原理是基本不变的.所以沉下心看清代码本质很重要,这次给大家带来的是手写RPC框架. 完整代码以及 ...

  3. 看了这篇你就会手写RPC框架了

    一.学习本文你能学到什么? RPC的概念及运作流程 RPC协议及RPC框架的概念 Netty的基本使用 Java序列化及反序列化技术 Zookeeper的基本使用(注册中心) 自定义注解实现特殊业务逻 ...

  4. 基于netty手写RPC框架

    代码目录结构 rpc-common存放公共类 rpc-interface为rpc调用方需要调用的接口 rpc-register提供服务的注册与发现 rpc-client为rpc调用方底层实现 rpc- ...

  5. 手写RPC框架

    https://www.bilibili.com/video/av23508597?from=search&seid=6870947260580707913 https://github.co ...

  6. 手撕RPC框架

    手撕RPC 使用Netty+Zookeeper+Spring实现简易的RPC框架.阅读本文需要有一些Netty使用基础. 服务信息在网络传输,需要讲服务类进行序列化,服务端使用Spring作为容器.服 ...

  7. 手写MQ框架(四)-使用netty改造梳理

    一.背景 书接上文手写MQ框架(三)-客户端实现,前面通过web的形式实现了mq的服务端和客户端,现在计划使用netty来改造一下.前段时间学习了一下netty的使用(https://www.w3cs ...

  8. java 从零开始手写 RPC (04) -序列化

    序列化 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RPC (02)-netty4 实现客户端和服务端 java 从零开始手写 RPC (03) 如何实 ...

  9. java 从零开始手写 RPC (05) reflect 反射实现通用调用之服务端

    通用调用 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RPC (02)-netty4 实现客户端和服务端 java 从零开始手写 RPC (03) 如何 ...

随机推荐

  1. tensorflow学习笔记(二)

    tensorflow中自带的mnist手写数字识别,运用最简单的单层神经网络,softmax激活函数,极客学院上说准确率有91%,我今天调整到了92%! import tensorflow as tf ...

  2. select count(1)和 select count(*)

    ),其实就是计算一共有多少符合条件的行. 1并不是表示第一个字段,而是表示一个固定值. 其实就可以想成表中有这么一个字段,这个字段就是固定值1,),就是计算一共有多少个1. 同理,),也可以,得到的值 ...

  3. python 得到列表的第二大的元素

    code #coding=utf- l=[,,,,,,] max1=l[] max2=l[] if(max1>max2): pass else: max1,max2=max2,max1 :]: ...

  4. git-中文乱码

    Windows系统的Git默认是不支持中文显示的,需要进行一系列的设置才能避免乱码的出现,下面总结如何配置Git使其支持中文显示. Git bash options UTF-8编码配置 1.首先进入g ...

  5. 2019SDN第7次上机作业

    2019SDN第7次上机作业 1.作业要求: 作业博客链接:https://edu.cnblogs.com/campus/fzu/fzusdn2019/homework/10165 2.具体操作步骤与 ...

  6. 百度编辑器(ueditor)踩坑,图片转存无法使用

    在使用 百度编辑器 的过程中碰到了一些问题,图片转存功能无法使用, 即便是疯狂地在官方 Demo.文档.论坛甚至是 GitHub 上也没找到理想的答案.(┗|`O′|┛) (真是日了狗) 问题描述 默 ...

  7. (四)Cisco dhcp snooping实例2-多交换机环境(DHCP服务器和DHCP客户端位于不同VLAN)

    试验拓扑 环境:dhcp server和客户端处于不同网段的情况 dhcp server的配置 no ip routing ip dhcp pool vlan27 network 172.28.27. ...

  8. SQL Server case when 实现分类汇总

    case when 实现分类汇总

  9. 解决electron-vue中无法Element的Tooltip组件

    打开文件:electron-vue/webpack.renderer.config.js 在大约21行左右找到 let whiteListedModules 将element-ui添加进去,最终如下所 ...

  10. Python 初级 6 循环

    一.一个简单的for循环 1 重复做相同的事 for looper in [1, 2, 3, 4, 5]: print("hello") 1 looper的值从1开始, 所以loo ...