手写一个rpc框架,实现思路利用netty框架+jdk动态代理+自定义协议+自定义编解码器+网络传输

技术难点:TCP粘包拆包问题,解决思路:客户端在往服务端发送消息时(编码),先要将消息的长度(一个int)写入与channel关联的buffer中。客户端在接受消息时,先判断消息的长度是不是够一个int,如果不够,等待下一次事件触发,如果够,判断可读的消息的长度是不是等于客户端传过来的长度,如果不够,继续等待下一次事件触发。自定义编解码器代码如下:
自定义编码器:

package codec;

import com.alibaba.fastjson.JSON;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

import java.util.Objects;

public class RpcEncoder extends MessageToByteEncoder {
    private Class clazz;

    public RpcEncoder(Class clazz) {
        this.clazz = clazz;
    }

    /**
     * 自定义编码方法实现 java--》byte
     * @param channelHandlerContext
     * @param o
     * @param byteBuf
     * @throws Exception
     */
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Object o, ByteBuf byteBuf) throws Exception {
        if(Objects.nonNull(clazz)&&clazz.isInstance(o)){
            System.out.println("编码方法被调用..encode");
            byte[] bytes = JSON.toJSONBytes(o);
            int length = bytes.length;
            byteBuf.writeInt(length);
            byteBuf.writeBytes(bytes);
        }
    }
}

自定义解码器:

package codec;

import com.alibaba.fastjson.JSON;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

public class RpcDecoder extends ByteToMessageDecoder {
    private Class clazz;

    public RpcDecoder(Class clazz) {
        this.clazz = clazz;
    }
    /**
     * 自定义解码器解码方法实现
     * @param channelHandlerContext
     * @param byteBuf
     * @param list
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throws Exception {
        System.out.println("解码方法被调用..decode");
        if(byteBuf.readableBytes()<4){
            return;
        }
        byteBuf.markReaderIndex();
        int length = byteBuf.readInt();
        if(byteBuf.readableBytes()

客户端代码(包括获取动态代理对象与初始化客户端):

package rpc.consumer;

import codec.RpcDecoder;
import codec.RpcEncoder;
import rpc.handler.ClientHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import protocol.RpcRequest;
import protocol.RpcResponse;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NettyClient {
    public static ExecutorService executor = Executors.newFixedThreadPool(4);
    public static boolean clientOk = false;
    private static ClientHandler clientHandler;
    public static Object getBean(final Class serviceClass){
        /**
         * 该方法返回目标对象的代理对象
         */
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{serviceClass}, (proxy, method, args) -> {
            System.out.println("客户端invoke方法执行..hello");
            if(null==clientHandler){
                initClient();
            }
            RpcRequest rpcRequest = new RpcRequest();
            rpcRequest.setRequestId(UUID.randomUUID().toString());
            rpcRequest.setInterfaceName(method.getDeclaringClass().getName());
            rpcRequest.setMethodName(method.getName());
            rpcRequest.setParamTypes(method.getParameterTypes());
            rpcRequest.setPatams(args);
            clientHandler.setRpcRequest(rpcRequest);
            return executor.submit(clientHandler).get();
        });
    }

    /**
     * 该方法初始化netty客户端
     */
    public static void initClient(){
        clientHandler= new ClientHandler();
        NioEventLoopGroup executors = new NioEventLoopGroup();
        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(executors)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .handler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new RpcEncoder(RpcRequest.class));
                            pipeline.addLast(new RpcDecoder(RpcResponse.class));
                            pipeline.addLast(clientHandler);
                        }
                    });
            System.out.println("客户端启动完毕");
            clientOk=true;
            bootstrap.connect("127.0.0.1", 9999).sync();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

客户端handler处理器:

package rpc.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import protocol.RpcRequest;
import protocol.RpcResponse;

import java.util.concurrent.Callable;

public class ClientHandler extends SimpleChannelInboundHandler implements Callable {

    private ChannelHandlerContext ctx;
    private RpcResponse rpcResponse;
    private RpcRequest rpcRequest;
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端与服务端建立连接..");
        this.ctx=ctx;
    }

    @Override
    protected synchronized void channelRead0(ChannelHandlerContext channelHandlerContext, RpcResponse rpcResponse) throws Exception {
        System.out.println("服务器返回数据..."+rpcResponse);
        this.rpcResponse=rpcResponse;
        notify();
    }
    //被代理对象调用,发送数据给服务器,等待被唤醒wait
    @Override
    public synchronized Object call() throws Exception {
        System.out.println("call 方法执行..");
        ctx.writeAndFlush(rpcRequest);
        wait();
        return rpcResponse.getData();
    }

    public void setRpcRequest(RpcRequest rpcRequest) {
        this.rpcRequest = rpcRequest;
    }
}

客户端controller(注意此处拿到的service是代理对象)


package rpc.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import rpc.consumer.NettyClient;
import rpcinterface.HelloService;
import rpcinterface.HiService;

import javax.annotation.PostConstruct;

@RestController
public class HelloController {

private HelloService helloService;
private HiService hiService;
@PostConstruct
private void init(){
    helloService = (HelloService) NettyClient.getBean(HelloService.class);
    hiService = (HiService)NettyClient.getBean(HiService.class);
}
@RequestMapping("/hello")
public String hello(String name){
    return helloService.hello(name);
}
@RequestMapping("/hi")
public String hi(String name){
    return hiService.hi(name);
}

}

自定义请求协议:
package protocol;


/**
 * 请求协议
 */
public class RpcRequest {

    private String requestId;
    private String interfaceName;
    private String methodName;
    private Class[] paramTypes;
    private Object[] patams;

    public String getRequestId() {
        return requestId;
    }

    public void setRequestId(String requestId) {
        this.requestId = requestId;
    }

    public String getInterfaceName() {
        return interfaceName;
    }

    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Class[] getParamTypes() {
        return paramTypes;
    }

    public void setParamTypes(Class[] paramTypes) {
        this.paramTypes = paramTypes;
    }

    public Object[] getPatams() {
        return patams;
    }

    public void setPatams(Object[] patams) {
        this.patams = patams;
    }
}

自定义响应协议:

package protocol;

/**
 * 响应协议
 */
public class RpcResponse {

    private String requestId;
    private Object data;

    public String getRequestId() {
        return requestId;
    }

    public void setRequestId(String requestId) {
        this.requestId = requestId;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

服务端初始化代码:

package provider;

import codec.RpcDecoder;
import codec.RpcEncoder;
import handler.NettyServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import protocol.RpcRequest;
import protocol.RpcResponse;

public class NettyServer {
    //nettyServer的初始化
    public static void startServer0(String hostName,int port){
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup worker = new NioEventLoopGroup(8);
        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss,worker)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new RpcDecoder(RpcRequest.class));//解码器
                            pipeline.addLast(new RpcEncoder(RpcResponse.class));//编码器
                            pipeline.addLast(new NettyServerHandler());//业务处理器
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(hostName, port).addListener(future -> {
                if(future.isSuccess()){
                    System.out.println("服务端启动成功,监听端口:"+port);
                }
            });
            channelFuture.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

服务端启动类:

package provider;

/**
 * 启动一个服务提供者,nettyServer
 */
public class ServerBootApplication {
    public static void main(String[] args) {
        NettyServer.startServer0("127.0.0.1",9999
        );
    }
}

服务端业务处理器Handler:

package handler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import protocol.RpcRequest;
import protocol.RpcResponse;
import util.InterfaceMapUtils;

import java.lang.reflect.Method;
import java.util.List;

public class NettyServerHandler extends SimpleChannelInboundHandler {

    @Override
    public void channelRead0(ChannelHandlerContext ctx, RpcRequest request) throws Exception {
        System.out.println("服务端收到请求");
        String requestId = request.getRequestId();
        String interfaceName = request.getInterfaceName();
        String methodName = request.getMethodName();
        Class[] paramTypes = request.getParamTypes();
        Object[] prams = request.getPatams();
        Class clazz = InterfaceMapUtils.interfaceMap.get(interfaceName);
        Object instance = clazz.newInstance();
        Method method = clazz.getMethod(methodName, paramTypes);
        Object invoke = method.invoke(instance, prams);
        RpcResponse response = new RpcResponse();
        response.setRequestId(requestId);
        response.setData(invoke);
        ctx.writeAndFlush(response);
        System.out.println("服务端处理请求完毕");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

服务端本地注册的容器

package util;

import rpcinterface.HelloService;
import rpcinterface.HiService;
import rpcinterface.impl.HelloServiceImpl;
import rpcinterface.impl.HiServiceImpl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 服务端本地注册的容器
 */
public class InterfaceMapUtils {

    public static Map> interfaceMap = new ConcurrentHashMap<>();
    static{
        Class helloServiceClass = HelloService.class;
        String hello = helloServiceClass.getName();
        Class hiServiceClass = HiService.class;
        String hi = hiServiceClass.getName();
        interfaceMap.put(hello, HelloServiceImpl.class);
        interfaceMap.put(hi, HiServiceImpl.class);
    }
}

服务端接口:

package rpcinterface;

public interface HelloService {
    String hello(String msg);
}

服务端实现类:

package rpcinterface.impl;

import rpcinterface.HelloService;

public class HelloServiceImpl implements HelloService {
    @Override
    public String hello(String msg) {
        System.out.println("收到客户端消息:"+msg);
        return "你好客户端,我已经收到你的消息:["+msg+"]";
    }
}

你可能感兴趣的:(手写一个rpc框架,实现思路利用netty框架+jdk动态代理+自定义协议+自定义编解码器+网络传输)