文章目录

  • 一、RPC基本介绍
  • 二、服务端
  • 1、定义接口及实现类
  • 2、定义服务端与客户端传输类
  • 3、服务端启动类
  • 4、服务端处理类
  • 三、客户端
  • 1、客户端代理类
  • 2、客户端处理类
  • 3、测试类


一、RPC基本介绍

RPC(Remote Procedure Call) —— 远程过程调用,是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。

两个或多个应用都分布在不同的服务器上,它们之间的调用就像是本地方法调用一样:

Netty实现一个简易RPC框架_java

二、服务端

1、定义接口及实现类

public interface IRpcService {

    //加
    int add(int a,int b);

    //减
    int sub(int a,int b);

    //乘
    int mult(int a,int b);

    //除
    int div(int a ,int b);
}

public interface IRpcHelloService {
    String hello(String name);
}
public class RpcHelloServiceImpl implements IRpcHelloService {
    public String hello(String name) {
        return "hello " + name + "!";
    }
}
public class RpcServiceImpl implements IRpcService {
    public int add(int a, int b) {
        return a + b;
    }

    public int sub(int a, int b) {
        return a - b;
    }

    public int mult(int a, int b) {
        return a * b;
    }

    public int div(int a, int b) {
        return a / b;
    }
}

2、定义服务端与客户端传输类

@Data
public class InvokerProtocol implements Serializable {

    private String className;  //类名
    private String methodName; //方法名称
    private Class<?>[] params; //形参列表
    private Object[] values;   //实参列表

}

3、服务端启动类

public class RpcRegistry {
    private int port;
    public RpcRegistry(int port) {
        this.port = port;
    }


    private void start() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        //扫描所有需要注册的类
        RegistryHandler.scannerClass("com.netty.rpc.provider");
        //将扫描到的类注册到一个容器中
        RegistryHandler.doRegister();
        try {
            ServerBootstrap server = new ServerBootstrap();
            server.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(Channel ch) throws Exception {
                            //接收课客户端请求的处理流程
                            ChannelPipeline pipeline = ch.pipeline();

                            int fieldLength = 4;
                            //通用解码器设置
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,fieldLength,0,fieldLength));
                            //通用编码器
                            pipeline.addLast(new LengthFieldPrepender(fieldLength));
                            //对象编码器
                            pipeline.addLast("encoder",new ObjectEncoder());
                            //对象解码器
                            pipeline.addLast("decoder",new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));

                            pipeline.addLast(new RegistryHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture future = server.bind(this.port).sync();
            System.out.println("RPC registry is start,listen at " + this.port);
            future.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

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

}

4、服务端处理类

public class RegistryHandler extends ChannelInboundHandlerAdapter {

    //注册中心容器
    private static ConcurrentHashMap<String,Object> registryMap = new ConcurrentHashMap<String, Object>();

    private static List<String> classNames = new ArrayList<String>();

    public RegistryHandler(){
        
    }

    public static void doRegister() {
        if(classNames.size() == 0){return;}

        for (String className : classNames) {
            try {
                Class<?> clazz = Class.forName(className);
                Class<?> i = clazz.getInterfaces()[0];
                registryMap.put(i.getName(),clazz.newInstance());
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static void scannerClass(String packageName) {
        URL url = RegistryHandler.class.getClassLoader().getResource(packageName.replaceAll("\\.","/"));
        File dir = new File(url.getFile());

        for (File file : dir.listFiles()) {

            //如果是文件夹,继续递归
            if(file.isDirectory()){
                scannerClass(packageName + "." + file.getName());
            }else {
                classNames.add(packageName + "." + file.getName().replace(".class","").trim());
            }
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Object result = new Object();
        InvokerProtocol request = (InvokerProtocol) msg;
        System.out.println("服务端收到消息");

        if(registryMap.containsKey(request.getClassName())){
            //用反射直接调用Provider的方法
            Object provider = registryMap.get(request.getClassName());
            Method method = provider.getClass().getMethod(request.getMethodName(),request.getParams());
            result = method.invoke(provider,request.getValues());
        }
        ctx.write(result);
        ctx.flush();
        ctx.close();
    }

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

三、客户端

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;
    }

    public static class MethodProxy implements InvocationHandler {
        private Class<?> clazz;
        public MethodProxy(Class<?> clazz) {
            this.clazz = clazz;
        }

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

            //封装请求的内容
            InvokerProtocol msg = new InvokerProtocol();
            msg.setClassName(this.clazz.getName());
            msg.setMethodName(method.getName());
            msg.setParams(method.getParameterTypes());
            msg.setValues(args);


            final RpcProxyHandler consumerHandler = new RpcProxyHandler();


            EventLoopGroup group = new NioEventLoopGroup();

            try {
                Bootstrap client = new Bootstrap();
                client.group(group)
                        .channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer() {
                            @Override
                            protected void initChannel(Channel ch) throws Exception {
                                //接收课客户端请求的处理流程
                                ChannelPipeline pipeline = ch.pipeline();

                                int fieldLength = 4;
                                //通用解码器设置
                                pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,fieldLength,0,fieldLength));
                                //通用编码器
                                pipeline.addLast(new LengthFieldPrepender(fieldLength));
                                //对象编码器
                                pipeline.addLast("encoder",new ObjectEncoder());
                                //对象解码器
                                pipeline.addLast("decoder",new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));

                                pipeline.addLast("handler",consumerHandler);
                            }
                        })
                        .option(ChannelOption.TCP_NODELAY, true);

                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 consumerHandler.getResponse();
        }
    }
}

2、客户端处理类

public class RpcProxyHandler extends ChannelInboundHandlerAdapter {

    private Object response;

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

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

    public Object getResponse() {
        return this.response;
    }
}

3、测试类

public class RpcConsumer {
    public static void main(String[] args) {

        IRpcHelloService rpcHello = RpcProxy.create(IRpcHelloService.class);
        System.out.println(rpcHello.hello("Tom"));

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

        System.out.println("8 + 2 = " + rpc.add(8,2));
        System.out.println("8 - 2 = " + rpc.sub(8,2));
        System.out.println("8 * 2 = " + rpc.mult(8,2));
        System.out.println("8 / 2 = " + rpc.div(8,2));

    }
}