TCP/IP学习笔记八:RPC(Netty和Spring)实现webServer框架
标签(空格分隔): RPC webService
基于RPC和NIO实现webService框架
webService的核心就是解决远程调用,现在基于RPC实现这种远程调用。
主要使用的是动态代理和反射机制实现客户端基于接口的远程调用。使用Netty和Spring进行开发RPC架构的webService。
详细开发思路和步骤在代码中以注释的形式展现。
说明:本实例没有考虑服务器端的接口有多个实现类的情况。
一、服务器端
将服务的启动(NIOServerBootstrap)交给Spring管理,Spring启动时进行初始化服务。
1.NIOServerBootstrap中的动态数据(port,channelHandlerAdapter)通过构造注入的方式进行传递。
2.NIOServerBootstrap 的start方法用子线程启动。如果不使用线程开启,会导致主线程阻塞。因为我们将启动引导交给Spring管理,在Spring初始化时开启,NIOServerBootstrap的启动会导致初始化阻塞,无法初始化其他启动项。
3.ServerRequestResponseHander实现ApplicationContextAware 拿到Spring工厂,实现ApplicationContextAwareSpring会自动注入工厂到ApplicationContext中
4.ServerRequestResponseHander的channelRead方法中,判断返回值是否为空(有些方法有返回值,有些方法返回值为void。result为空返回给客户端会报空指针)引入一个NullWritable类(单例【饿汉式】)。
服务的启动引导类
package com.motui.rpc.Server; import com.motui.rpc.common.ObjectCodec; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; /** * 服务的引导类 * @author MOTUI * */ public class NIOServerBootstrap { private int port; //端口号 private ChannelHandlerAdapter channelHandlerAdapter; //IO事件处理类 private ServerBootstrap serverBootstrap; //NIOServerSocketChannel的服务引导 private EventLoopGroup boss; //线程池 boss(请求转发) worker(IO事件处理) private EventLoopGroup worker; //worker(IO事件处理) /** * 构造函数 * 初始化参数 * @param port 服务器端口号 * @param channelHandlerAdapter IO事件处理类 */ public NIOServerBootstrap(int port, ChannelHandlerAdapter channelHandlerAdapter) { super(); this.port = port; this.channelHandlerAdapter = channelHandlerAdapter; //初始化参数 serverBootstrap = new ServerBootstrap(); boss = new NioEventLoopGroup(); worker = new NioEventLoopGroup(); //绑定线程池 serverBootstrap.group(boss, worker); //设置服务类 serverBootstrap.channel(NioServerSocketChannel.class); } /** * 开启服务 * 如果不使用线程开启,会导致主线程阻塞。 * 因为我们将启动引导交给Spring管理,在Spring初始化时开启,NIOServerBootstrap的启动会导致初始化阻塞, * 无法初始化其他启动项。 */ public void start(){ new Thread(){ @Override public void run() { try { //绑定IO处理事件 serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>(){ @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new LengthFieldPrepender(2)); ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2)); ch.pipeline().addLast(new ObjectCodec()); //将channelHandlerAdapter添加到队列 ch.pipeline().addLast(NIOServerBootstrap.this.channelHandlerAdapter); } }); //绑定服务器启动端口 System.out.println("服务器开始监听:"+NIOServerBootstrap.this.port+