手写RPC框架(netty+zookeeper)

  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>

猜你喜欢

转载自www.cnblogs.com/hhhshct/p/11544734.html