基于Netty手写的Rpc框架

基于Netty手写的rpc框架时序图

基于Netty手写的Rpc框架_第1张图片

本项目一共分为三个模块:rpcServer、rpcClient、rpcCommon

rpcCommon的依赖

  
    
      io.netty
      netty-all
      5.0.0.Alpha2
    

    
    
      org.reflections
      reflections
      0.9.11
    
  

rpcServer、rpcClient的依赖


  
    rpc
    rpc-common
    1.0-SNAPSHOT
  

 

rpcCommon目录结构

 

rpcCommon--ClassInfo类

package com.hk.common;

import java.io.Serializable;

/**
 * 使用JDK的序列化技术必须实现接口Serializable
 */
public class ClassInfo implements Serializable {

    private int id;
    private String className;
    private String methodName;
    private Class[] parameterTypes;
    private Object [] paramters;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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 Class[] getParameterTypes() {
        return parameterTypes;
    }

    public void setParameterTypes(Class[] parameterTypes) {
        this.parameterTypes = parameterTypes;
    }

    public Object[] getParamters() {
        return paramters;
    }

    public void setParamters(Object[] paramters) {
        this.paramters = paramters;
    }
}

接口

有参接口

package com.hk.common;
public interface HasArgsHelloService {
    String hello(String msg);
}

无参接口
package com.hk.common;

public interface NoArgsHelloService {
    String hello();
}

rpcServer目录结构

基于Netty手写的Rpc框架_第2张图片

rpc服务端代码

//利用netty创建服务ServerBootstrap,粘合两个NioEventLoopGroup,配置端口ip,设置编码解码信息

package com.hk.rpc.server;

import com.hk.rpc.server_stub.RpcServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

public class RpcServer {

    public static void main(String[] args) {
        RpcServer.start("127.0.0.1", 9999);
    }

    public static void start(String ip, Integer port) {
        //创建boss线程组(有点像负责招人的包工头)
        NioEventLoopGroup boss = new NioEventLoopGroup();
        //创建建立链接的线程
        NioEventLoopGroup worker = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 128)
                .childHandler(new ChannelInitializer() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ObjectEncoder());
                        ch.pipeline().addLast(new ObjectDecoder(1024 * 64, ClassResolvers.cacheDisabled(null)));
                        ch.pipeline().addLast(new RpcServerHandler());
                    }
                });
            //bind初始化端口是异步的,但调用sync则会同步阻塞等待端口绑定成功
            ChannelFuture future = bootstrap.bind(ip, port).sync();
            System.out.println(ip + ":服务已启动,端口为:" + port);
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

服务端处理器代码

//真正通过反射找到实现类,调用方法返回结果

package com.hk.rpc.server_stub;

import com.hk.common.ClassInfo;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import java.lang.reflect.Method;
import java.util.Set;
import org.reflections.Reflections;

public class RpcServerHandler extends ChannelHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //获取调用信息,寻找服务实现类
        ClassInfo classInfo = (ClassInfo) msg;
        String implName = getImplClassName(classInfo.getClassName());
        Class clazz = Class.forName(implName);
        Method method = clazz.getMethod(classInfo.getMethodName(), classInfo.getParameterTypes());
        Object result = method.invoke(clazz.newInstance(), classInfo.getParamters());
        ctx.writeAndFlush(result);
    }

    private String getImplClassName(String interfaceName) throws ClassNotFoundException {
        Class interClass = Class.forName(interfaceName);
        String servicePath = "com.hk.rpc.service";
        Reflections reflections = new Reflections(servicePath);
        Set implClasses = reflections.getSubTypesOf(interClass);
        if (implClasses.isEmpty()) {
            System.err.println("impl class is not found!");
        } else if (implClasses.size() > 1) {
            System.err.println("there are many impl classes, not sure invoke which");
        } else {
            Class[] classes = implClasses.toArray(new Class[1]);
            return classes[0].getName();
        }
        return null;
    }
}


两个实现类代码

package com.hk.rpc.service;

import com.hk.common.HasArgsHelloService;

public class HasArgsHelloServiceImpl implements HasArgsHelloService {

    public String hello(String msg) {
        return "hello "+msg;
    }
}

package com.hk.rpc.service;

import com.hk.common.NoArgsHelloService;

public class NoArgsHelloServiceImpl implements NoArgsHelloService {

    public String hello() {
        return "hello";
    }
}

项目结构:rpcClient

基于Netty手写的Rpc框架_第3张图片

客户端代码

//利用代理类来测试流程

package com.hk.rpc.server;

import com.hk.common.HasArgsHelloService;
import com.hk.common.NoArgsHelloService;
import com.hk.rpc.client_stub.RpcProxy;

public class RPCClient {

    public static void main(String[] args){
        NoArgsHelloService noArgsHelloService = (NoArgsHelloService) RpcProxy.create(NoArgsHelloService.class);
        System.out.println(noArgsHelloService.hello());

        HasArgsHelloService hasArgsHelloService = (HasArgsHelloService) RpcProxy.create(HasArgsHelloService.class);
        System.out.println(hasArgsHelloService.hello("hello 黄凯!"));
    }

}

客户端处理器代码

//接收到服务端的请求,并赋值以及关闭连接

package com.hk.rpc.client_stub;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;


public class RpcClientHandler extends ChannelHandlerAdapter {

    /**
     * RPC调用返回的结果
     */
    private Object rpcResult;

    public Object getRpcResult() {
        return rpcResult;
    }

    public void setRpcResult(Object rpcResult) {
        this.rpcResult = rpcResult;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        setRpcResult(msg);
        ctx.close();
    }
}

客户端代码类

//根据接口类信息通过jdk代理来调用实现类,在Bootstrap建立连接后,添加客户端处理器,并返回信息

package com.hk.rpc.client_stub;

import com.hk.common.ClassInfo;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class RpcProxy {

    public static Object create(final Class clazz) {
        return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //构造调用信息
                ClassInfo classInfo = new ClassInfo();
                classInfo.setClassName(clazz.getName());
                classInfo.setMethodName(method.getName());
                classInfo.setParameterTypes(method.getParameterTypes());
                classInfo.setParamters(args);

                //使用netty发送调用信息给服务提供方
                NioEventLoopGroup group = new NioEventLoopGroup();
                //
                Bootstrap bootstrap = new Bootstrap();
                final RpcClientHandler rpcClientHandler = new RpcClientHandler();
                try {
                    bootstrap.group(group)
                        .channel(NioSocketChannel.class)
                        .option(ChannelOption.SO_KEEPALIVE, true)
                        .option(ChannelOption.TCP_NODELAY, true)
                        .handler(new ChannelInitializer() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast(new ObjectEncoder());
                                //反序列化对象时指定类解析器,null表示使用默认的类加载器
                                ch.pipeline().addLast(new ObjectDecoder(1024 * 64, ClassResolvers.cacheDisabled(null)));
                                ch.pipeline().addLast(rpcClientHandler);

                            }
                        });
                    //connect是异步的,但调用其future的sync则是同步等待连接成功
                    ChannelFuture future = bootstrap.connect("127.0.0.1", 9999).sync();
                    //同步等待调用信息发送成功
                    future.channel().writeAndFlush(classInfo).sync();
                    //同步等待RPCClientHandler的channelRead被触发后(意味着收到了调用结果)
                    future.channel().closeFuture().sync();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    group.shutdownGracefully();
                }

                //返回调用结果
                return rpcClientHandler.getRpcResult();
            }
        });
    }
}

最后测试,先启动RpcServer服务类,打印了信息之后,再启动客户端RPCClient进行测试

测试结果如下:

hello
hello hello 黄凯!

测试成功!!!

 

 

你可能感兴趣的:(netty,rpc)