Netty学习(八)----实现RPC-demo (能通就行版)

一: 交互流程

在这里插入图片描述

在这里插入图片描述

说明:

  1. client stub 接收到方法调用后 对参数、方法签名封装成易网络传输的消息体
  2. client stub 将消息进行编码,并发送至服务端
  3. server stub 接收消息并进行解码
  4. server stub 根据解码结果调用本地的服务
  5. server本地服务应答server stub
  6. servier stub 将执行结果进行封装编码至消费方
  7. 消费方进行解码,告知client stub 的调用者

二: 相关类介绍

HelloService :提供者 与消费者 所使用的API

public interface HelloService {

    String hello(String request);

}

NettyServer :提供者服务启动项目,其中的NettyServerHandler 见下。

 public class NettyServer {

    public static void startServer(String hostname, int port) {

        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup(4);

        try {

            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new StringEncoder());
                            ch.pipeline().addLast(new NettyServerHandler());
                        }
                    });

            ChannelFuture channelFuture = serverBootstrap.bind(hostname, port).sync();

            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();

        }


    }

}

NettyServerHandler :调用本地服务处理类型,其中msg暂时以interface#method#params1=value1&params2=value2 的方式进行硬编码规定。

public class NettyServerHandler extends ChannelInboundHandlerAdapter {


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        //获取客户端发送消息,并发转发到本地method
        System.out.println("PARAMS msg = " + msg);

        //模拟协议快速检查  interface#method#params1=value1&params2=value2
        if (checkUrls(msg.toString())) {

            String[] urls = msg.toString().split("#");

            if (urls[0].equals("HelloService") && urls[1].equals("hello")) {

                String invokeRes = new HelloServiceImpl().hello(urls[2]);

                ctx.writeAndFlush(invokeRes);

                System.out.println("finished,res =  "+invokeRes);
            }

        }
    }


    //simple check
    private Boolean checkUrls(String url) {
        return url.contains("#");
    }
}

HelloServiceImpl :调用本地服务实现类

public class HelloServiceImpl implements HelloService {

    @Override
    public String hello(String request) {

        System.out.println(" interface from call PARAMS :" + request);

        String res = new Date() + " echo from server :";

        return res + request;

    }

}

ClientBootstrap :客户端启动类

public class ClientBootstrap {

    public static final String protocolPrefix = "HelloService#hello#";

    public static void main(String[] args) {

        NettyClient client = new NettyClient();

        HelloService helloServiceProxy = (HelloService) client.getProxyBean(HelloService.class, protocolPrefix);

        String result = helloServiceProxy.hello("say hello");

        System.out.println("main result = "+result);

    }


}

NettyClient :客户端 netty 启动类

public class NettyClient {

    private static ExecutorService executorService = Executors.newFixedThreadPool(2);
    private static NettyClientHandler client;

    public Object getProxyBean(Class serviceClass, final String providerUrls) {

        return Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),//class loader
                new Class[]{serviceClass},//impl Interfaces
                (proxy, method, args) -> {  //InvocationHandler

                    if (client == null) initClient();

                    client.setParams(providerUrls + args[0]);

                    return executorService.submit(client).get();


                });
    }


    public static void initClient() {

        client = new NettyClientHandler();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(new NioEventLoopGroup())
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringEncoder());
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(client);

                    }
                });

        try {
            bootstrap.connect("127.0.0.1", 8080).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }

}

NettyClientHandler :客户端对于服务端消息应答处理类

public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {

    private ChannelHandlerContext context;
    private String result;
    private String params;


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //set context on channel active
        context = ctx;
    }

    @Override
    public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("channelRead" + Thread.currentThread().getName() +" bean" +this.hashCode());
        result = msg.toString();
        System.out.println("receive date = " + new Date());
        notify();

    }

    //提供代理对象调用,发送给server stub , 当read收到结果之前置于wait状态,
    @Override
    public synchronized Object call() throws Exception {

        System.out.println("call" + Thread.currentThread().getName()+" bean" +this.hashCode());

        context.writeAndFlush(params);

        wait();

        return result;

    }

    void setParams(String params) {
        this.params = params;
    }


}

三: 总结

使用netty进行原始、最简单的rpc调用实现中:

  • client基于netty做网络传输,在收到服务端有可读事件之前,本地调用的方法形成阻塞,直置被可读事件接收。
  • client调用rpc方法,使用代理进行调用,减少侵入式。
  • 该demo 中 server处理事情小于client很多,对于客户端发送过来的数据报文解析,知晓执行类是哪个,并做相应调用,最终应答即可。
  • rpc-demo能通版还能优化的地方大概有一个银河系呢么大,但是随着该demo跑通结束,对Netty有了第一轮初步认识,可做接来下的学习了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值