基于netty手写rpc

1 篇文章 0 订阅

rpc简介

RPC是远程过程调用(Remote Procedure Call),比如Dubbo框架就是使用rpc原理。
百度百科

api模块–接口声明和协议定义

1.定义netty服务端和客户端的通信协议(即消息内容)

public class RpcProtocol implements Serializable {
  /**类名**/
  private String className;
  /**方法名**/
  private String methodName;
  /**参数类型**/
  private Class<?>[] parames;
  /**参数值**/
  private Object[] values;
}

2. 接口声明

public interface IRpcService {
  String test(String test);
}

远程服务提供者server端–编写

1.实现接口

public class RpcServiceimpl implements IRpcService {
  @Override
  public String test(String test) {
    return "hello " + test + "!";
  }
}

2.编写服务提供

public class RpcProvider {
  private int port;
  public RpcProvider(int port) {
    this.port = port;
  }
  public void start(){
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workGroup = new NioEventLoopGroup();
    try {
      ServerBootstrap bootstrap = new ServerBootstrap();
      bootstrap.group(bossGroup,workGroup)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitializer<SocketChannel>() {
          @Override
          protected void initChannel(SocketChannel socketChannel) throws Exception {
            ChannelPipeline pipeline = socketChannel.pipeline();
            //协议解码器
            pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
            //协议编码器
            pipeline.addLast(new LengthFieldPrepender(4));
            //对象参数类型编码器
            pipeline.addLast(new ObjectEncoder());
            //对象参数类型解码器
            pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
            pipeline.addLast(new RpcHandler());
          }
        })
        //主线程 线程最大数量128
        .option(ChannelOption.SO_BACKLOG,128)
        //子线程配置 保存长连接
        .childOption(ChannelOption.SO_KEEPALIVE,true);
      ChannelFuture future = bootstrap.bind(port).sync();
      System.out.println("Rpc start listen at " + port);
      future.channel().closeFuture().sync();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      bossGroup.shutdownGracefully();
      workGroup.shutdownGracefully();
    }
  }
}

3.netty handler 编写

public class RpcHandler extends ChannelInboundHandlerAdapter {
  //保存服务实现的类实例
  public static ConcurrentHashMap<String, Object> serviceImplMap = new ConcurrentHashMap<>();
  //保存服务实现的类名
  public List<String> classNames = new ArrayList<>();

  public RpcHandler() {
    //递归扫描
    scannerClass("com.aiden.serviceimpl");
    doRegister();
  }

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    Object result = new Object();
    RpcProtocol request = (RpcProtocol) msg;
    if (serviceImplMap.containsKey(request.getClassName())) {
      Object clazz = serviceImplMap.get(request.getClassName());
      Method method = clazz.getClass().getMethod(request.getMethodName(), request.getParames());
      result = method.invoke(clazz, request.getValues());
    }
    ctx.write(result);
    ctx.flush();
    ctx.close();
  }

  //扫描实现的class
  private void scannerClass(String packageName) {
    URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
    File dir = new File(url.getFile());
    for (File file : dir.listFiles()) {
      if (file.isDirectory()) {
        scannerChildFile(packageName + "." + file.getName(), classNames, file);
      } else {
        classNames.add(packageName + "." + file.getName().replace(".class", "").trim());
      }
    }
  }

  private void scannerChildFile(String packageName, List<String> classNames, File child) {
    for (File file : child.listFiles()) {
      if (file.isDirectory()) {
        scannerChildFile(packageName + "." + file.getName(), classNames, file);
      } else {
        classNames.add(packageName + "." + file.getName().replace(".class", "").trim());
      }
    }
  }

  private void doRegister() {
    if (classNames.size() == 0) {
      return;
    }
    for (String className : classNames) {
      try {
        Class<?> clazz = Class.forName(className);
        Class<?> serviceInterface = clazz.getInterfaces()[0];
        serviceImplMap.put(serviceInterface.getName(), clazz.newInstance());
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

4.启动类

public class RpcRemoteStart {
  public static void main(String[] args) {
    new RpcProvider(8080).start();
  }
}

本地rpc调用编写

1.编写代理类

public class RpcProxy {
  public static <T> T create(Class<?> clazz) {
    MethodProxy proxy = new MethodProxy(clazz);
    Class<?> [] interfaces = clazz.isInterface()?new Class[]{clazz}:clazz.getInterfaces();
    T result = (T) Proxy.newProxyInstance(clazz.getClassLoader(),interfaces,proxy);
    return result;
  }
  private static class MethodProxy implements InvocationHandler{
    private Class<?> clazz;

    public MethodProxy(Class<?> clazz) {
      this.clazz = clazz;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this,args);
      } else {
        return rpcInvoke(proxy,method,args);
      }
    }

    private Object rpcInvoke(Object proxy, Method method, Object[] args) {
      RpcProtocol msg = new RpcProtocol();
      msg.setClassName(this.clazz.getName());
      msg.setMethodName(method.getName());
      msg.setValues(args);
      msg.setParames(method.getParameterTypes());
      final RpcProxyHandler rpcProxyHandler = new RpcProxyHandler();
      EventLoopGroup group = new NioEventLoopGroup();
      try {
        Bootstrap client = new Bootstrap();
        client.group(group)
          .channel(NioSocketChannel.class)
          .option(ChannelOption.TCP_NODELAY,true)
          .handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
              ChannelPipeline pipeline = ch.pipeline();
              //协议解码器
              pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
              //协议编码器
              pipeline.addLast(new LengthFieldPrepender(4));
              //对象参数类型编码器
              pipeline.addLast(new ObjectEncoder());
              //对象参数类型解码器
              pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
              pipeline.addLast(rpcProxyHandler);
            }
          });
        ChannelFuture future = client.connect("localhost",8080).sync();
        future.channel().writeAndFlush(msg).sync();
        future.channel().closeFuture().sync();
      } catch (Exception e) {
        e.printStackTrace();
      } finally {
        group.shutdownGracefully();
      }
      return rpcProxyHandler.getResponse();
    }
  }
}

2.netty handler 处理类编写

public class RpcProxyHandler extends ChannelInboundHandlerAdapter {
  private Object response;

  public Object getResponse() {
    return response;
  }

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    response = msg;
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    System.out.println("client exception is generate");
  }
}

3.客户端启动类

public class ClientStart {
  public static void main(String[] args) {
    IRpcService rpcService = RpcProxy.create(IRpcService.class);
    System.out.println(rpcService.test("Aiden"));
  }
}

结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值