基于netty手写rpc

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;

}

12345678910

2. 接口声明

public interface IRpcService {

  String test(String test);

}

123

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

1.实现接口

public class RpcServiceimpl implements IRpcService {

  @Override

  public String test(String test) {

    return "hello " + test + "!";

  }

}

123456

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() {

          @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();

    }

  }

}

123456789101112131415161718192021222324252627282930313233343536373839404142

3.netty handler 编写

public class RpcHandler extends ChannelInboundHandlerAdapter {

  //保存服务实现的类实例

  public static ConcurrentHashMap serviceImplMap = new ConcurrentHashMap<>();

  //保存服务实现的类名

  public List 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 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();

      }

    }

  }

}

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364

4.启动类

public class RpcRemoteStart {

  public static void main(String[] args) {

    new RpcProvider(8080).start();

  }

}

12345

本地rpc调用编写

1.编写代理类

public class RpcProxy {

  public static 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() {

            @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();

    }

  }

}

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263

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");

  }

}

1234567891011121314151617

3.客户端启动类

public class ClientStart {

  public static void main(String[] args) {

    IRpcService rpcService = RpcProxy.create(IRpcService.class);

    System.out.println(rpcService.test("Aiden"));

  }

}

123456

结果

你可能感兴趣的:(基于netty手写rpc)