RPC 全称 Remote Procedure Call(远程过程调用),本质上是在两个不同机器之间通过网络传输数据,但是在本地看来是通过接口调用一样。
引入依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.45.Final</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
编写公共类
定义 Class 信息类
@Data
public class ClassInfo implements Serializable {
private static final long serialVersionUID = 1L;
private Class<?> klass;
private String classname;
private ClassLoader classLoader;
private Class<?>[] interfaces;
}
定义远程传输的对象类
@Data
public class RpcInfo implements Serializable {
private static final long serialVersionUID = 1L;
private String classname;
private String methodName;
private Object[] args;
private Class<?>[] argsTypes;
public RpcInfo(String classname, String methodName, Object[] args, Class<?>[] argsTypes) {
this.classname = classname;
this.methodName = methodName;
this.args = args;
this.argsTypes = argsTypes;
}
}
编写服务端
首先定义需要暴露接口和的实现类。这两个类在包jonkee.netty.rpc.server.rpcsevice
里面。
public interface UserService {
Map<String, Object> findById(String userId);
}
public class UserServiceImpl implements UserService {
@Override
public Map<String, Object> findById(String userId) {
Map<String, Object> hashMap = new HashMap<>();
hashMap.put("id", userId);
hashMap.put("name", "鲁班" + userId + "号");
return hashMap;
}
}
然后定义 ChannelHandler。
public class RpcServerHandler extends SimpleChannelInboundHandler<Object> {
//需要暴露的接口的包名
private static final String BASE_SERVICE_PATH = "jonkee.netty.rpc.server.rpcsevice";
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
System.out.println("收到请求");
RpcInfo rpcInfo = (RpcInfo) msg;
Reflections reflections = new Reflections(BASE_SERVICE_PATH);
Class clazz = Class.forName(BASE_SERVICE_PATH + rpcInfo.getClassname().substring(rpcInfo.getClassname().lastIndexOf(".")));
// 通过反射框架获取客户端需要调用的实现类
Set<Class<?>> classSet = reflections.getSubTypesOf(clazz);
if (classSet.isEmpty()) {
throw new Exception("不合法的服务调用");
}
if (classSet.size() > 1) {
throw new Exception("实现类不止一个");
}
// 通过反射获取本地实例
Class impl = (Class) classSet.toArray()[0];
Method method = impl.getMethod(rpcInfo.getMethodName(), rpcInfo.getArgsTypes());
// 反射获取结果
Object invoke = method.invoke(impl.newInstance(), rpcInfo.getArgs());
channelHandlerContext.channel().writeAndFlush(invoke);
System.out.println("返回数据成功");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端连上了");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
编写服务端启动类。
public class RpcServer {
public static void main(String[] args) throws InterruptedException {
new RpcServer().start();
}
private void start() throws InterruptedException {
ServerBootstrap serverBootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
serverBootstrap.group(boss, worker)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(new RpcServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();
System.out.println("Rpc server started successfully");
channelFuture.channel().closeFuture().sync();
}
}
编写客户端
定义一个本地接口,跟服务端的一样。
public interface UserService {
Map<String, Object> findById(String userId);
}
编写代理类,先定义一个 ChannelHandler。
public class ClientChannelHandler extends ChannelInboundHandlerAdapter {
private Object result;
public Object getResult() {
return result;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
this.result = msg;
// 关闭上下文
ctx.close();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
编写代理类。
public class ClientProxy {
public static final Map<String, ClassInfo> CLASS_CACHE = new ConcurrentHashMap<>();
public static Object proxy(Class<?> clazz) {
// 从缓存中获取类信息
ClassInfo classInfo = getClassInfoFromCache(clazz);
final ClassInfo info = classInfo;
return Proxy.newProxyInstance(classInfo.getClassLoader(), classInfo.getInterfaces(), (proxy, method, args) -> {
// 封装远程过程调用需要的信息
RpcInfo rpcInfo = new RpcInfo(info.getClassname(), method.getName(), args, method.getParameterTypes());
ClientChannelHandler clientChannelHandler = new ClientChannelHandler();
Bootstrap bootstrap = new Bootstrap();
EventLoopGroup group = new NioEventLoopGroup(1);
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(clientChannelHandler);
}
});
// 连接服务器
ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress("localhost", 8888)).sync();
Channel channel = channelFuture.channel();
channel.writeAndFlush(rpcInfo).sync();
System.out.println("正在获取数据");
channel.closeFuture().sync();
System.out.println("获取到了数据");
return clientChannelHandler.getResult();
});
}
private static ClassInfo getClassInfoFromCache(Class<?> clazz) {
ClassInfo classInfo = CLASS_CACHE.get(clazz.getName());
if (classInfo == null) {
classInfo = new ClassInfo();
classInfo.setKlass(clazz);
classInfo.setClassLoader(clazz.getClassLoader());
if (clazz.isInterface()) {
classInfo.setInterfaces(new Class[]{clazz});
} else {
classInfo.setInterfaces(clazz.getInterfaces());
}
classInfo.setClassname(clazz.getName());
CLASS_CACHE.put(clazz.getName(), classInfo);
}
return classInfo;
}
}
编写调用者。
public class ClientMain {
public static void main(String[] args) {
UserService userService = (UserService) ClientProxy.proxy(UserService.class);
for (int i = 1; i < 5; i++) {
Map<String, Object> userInfo = userService.findById(String.valueOf(i));
System.out.println(userInfo);
}
}
}
使用
启动服务器
Rpc server started successfully
启动客户端
正在获取数据
获取到了数据
{name=鲁班1号, id=1}
正在获取数据
获取到了数据
{name=鲁班2号, id=2}
正在获取数据
获取到了数据
{name=鲁班3号, id=3}
正在获取数据
获取到了数据
{name=鲁班4号, id=4}
可以看到,客户端通过代理将请求信息发送到服务端,服务端返回之后客户端获取到了数据。