基于Netty手写的Rpc框架

1 篇文章 0 订阅

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

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

rpcCommon的依赖

  <dependencies>
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>5.0.0.Alpha2</version>
    </dependency>

    <!-- 服务提供方根据调用信息反射获取实现类时需要 -->
    <dependency>
      <groupId>org.reflections</groupId>
      <artifactId>reflections</artifactId>
      <version>0.9.11</version>
    </dependency>
  </dependencies>

rpcServer、rpcClient的依赖

<dependencies>
  <dependency>
    <groupId>rpc</groupId>
    <artifactId>rpc-common</artifactId>
    <version>1.0-SNAPSHOT</version>
  </dependency>
</dependencies>

 

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目录结构

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<SocketChannel>() {
                    @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<Class> 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

客户端代码

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

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<SocketChannel>() {
                            @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 黄凯!

测试成功!!!

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值