为什么要手写?
主要是 为了 理解下 RPC 的一个具体编程模型
和他实现的一些细节
其实就是一个编程模型的 理解 和 实践 过程
基于netty框架
我们之前 学过netty框架的一个 编程模型
server client
基于事件驱动的模式。
上一个例子我们 把 数据传递到服务器
然后 服务器给我们返回数据
中间通过 netty的网络连接 实现打通
那么我们就会想 是否可以 把 传递过去的数据
变成一个抽象,
然后 服务器端的 数据获取 及处理 编程 具体的 实现类
客户端的 模拟调用
变成面向接口
简单画了个图片给大家理解下
说白了就是 客户端 现在 要利用 service 接口
动态生成代理对象
而动态代理的实现细节中加入 和 网络交互
把 具体的代码实现放到了远程服务器。
远程服务器把结果通过网络返回给客户端
客户端再交由代理对象返回
于是我们感知到的就是
本地调用的返回
看起来很你牛逼的样子
不错确实很牛逼
代码
Service.java
public interface Service {
String sayHelloWithName(String name);
}
这个就是一个服务接口咯
没啥可说的
他接收一个参数
然后返回一个字符串。
ServiceProvider.java
public class ServiceProvider implements Service {
@Override
public String sayHelloWithName(String name) {
return "hello "+name;
}
}
这个是 service 的具体实现
没啥可说的
就是拿到了 入参 然后 稍微处理下
加了个hello 然后返回了
我们这里只是模拟下
ServiceServer.java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class ServiceServer {
private int port = 0;
public ServiceServer(int port) {
this.port = port;
}
//接收请求
NioEventLoopGroup boss = new NioEventLoopGroup();
//处理请求
NioEventLoopGroup worker = new NioEventLoopGroup();
//用来启动server
ServerBootstrap bootstrap = new ServerBootstrap();
public void run(){
//告诉用户 输入在哪个端口上
System.out.println("running on port :"+port);
try {
//设置工作组
bootstrap.group(boss,worker);
//基于什么样的管道来进行通信
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
//解码
p.addLast(new StringDecoder());
//编码
p.addLast(new StringEncoder());
//逻辑的实现
p.addLast(new ServiceProviderHandler());
}
});
//绑定ip 和端口
ChannelFuture channelFuture = bootstrap.bind("127.0.0.1", port).sync();
//启动起来
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
//将worker close
worker.shutdownGracefully();
boss.shutdownGracefully();
}
}
public static void main(String[] args) {
ServiceServer serviceServer = new ServiceServer(9999);
serviceServer.run();
}
}
这个就是一个编程模型
netty作为网络服务器
这个类就是一个 server端的代码
万年不变的哦
都是这么写的
大家可以在网上找到很多类似代码
不过我这个是 参照 netty官网 规范写的啊
大家可以借鉴下
server端 我们定有两个 NioEventLoopGroup
一个是boss 一个是 worker
boss 接收请求
worker 处理请求
别的没啥可说的了 照着写
ServiceProviderHandler.java
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
public class ServiceProviderHandler extends ChannelHandlerAdapter {
private static final Service SERVICE = new ServiceProvider();
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String s = msg.toString();
System.out.println("get str from client:"+s);
ctx.writeAndFlush(SERVICE.sayHelloWithName(s));
}
}
这个类正式 如他所说的 handler 或者是 adapter
其实 netty也看到了这个 地方的不妥
所以他们现在都叫 adapter了
你可以去看最新的 netty代码 之前 这部分 是 handler
现在都叫 adapter
了
这个地方就是 让 具体实现 接收网络传输数据
然后 自己 逻辑处理下
然后 通过网络传出 结果数据
这个地方 我们称为 adapter
ServiceClient.java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executo