RPC框架的实现原理
服务暴露方通过Socket接受到服务消费方的请求方法调用,通过反序列化解析出消费方调用的方法、参数,通过反射调用服务实现类的方法获取方法调用的结果,将调用结果使用socket回写给服务消费方。
服务消费方通过动态代理透明的对服务进行调用,其中代理对象的方法调用通过socket将方法、参数相关信息写给服务暴露方,在通过socket将暴露方的调用结果回写给消费者
使用Netty实现一个简单的RPC框架
服务暴露Export.java
package ning.zhou.rpc.netty.rpc;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @author 周宁
* @Date 2019-10-10 15:48
*/
public class Export {
/**
* 已注册服务
*/
private Map<Class, Object> registried = new HashMap<>();
public void setRegistried(Map<Class, Object> registried) {
this.registried = registried;
}
public void export(int port) {
ServerBootstrap serverBootstrap = new ServerBootstrap();
EventLoopGroup bossGroup = new NioEventLoopGroup();
try {
serverBootstrap.group(bossGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast(new ObjectDecoder(1024, ClassResolvers
.cacheDisabled(this.getClass().getClassLoader())));
channel.pipeline().addLast(new ObjectEncoder());
channel.pipeline().addLast(new SimpleChannelInboundHandler<Invoker>() {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Invoker invoker) throws Exception {
Object obj = registried.get(invoker.getClss());
Class<?>[] parameterTypes = invoker.getParameterTypes();
Object[] arguments = invoker.getArguments();
String methodName = invoker.getMethodName();
Method method = obj.getClass().getMethod(methodName, parameterTypes);
Object result = method.invoke(obj, arguments);
channelHandlerContext.writeAndFlush(result);
}
});
}
});
ChannelFuture f = serverBootstrap.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
}
}
}
服务引用Refer.java
package ning.zhou.rpc.netty.rpc;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import java.lang.reflect.Proxy;
import java.util.concurrent.CountDownLatch;
/**
* @author 周宁
* @Date 2019-10-10 15:49
*/
public class Refer {
public static <T> T refer(Class<T> clss, final String host, final int port) {
return (T) Proxy.newProxyInstance(clss.getClassLoader(), new Class<?>[]{clss}, (proxy, method, args) -> {
final CountDownLatch countDownLatch = new CountDownLatch(1);
ResultRefer resultRefer = new ResultRefer();
EventLoopGroup group = null;
try {
group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel channel) throws Exception {
channel.pipeline().addLast(new ObjectDecoder(1024, ClassResolvers
.cacheDisabled(this.getClass().getClassLoader())));
channel.pipeline().addLast(new ObjectEncoder());
channel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Invoker invoker = new Invoker();
invoker.setArguments(args);
invoker.setMethodName(method.getName());
invoker.setParameterTypes(method.getParameterTypes());
invoker.setClss(clss);
ctx.writeAndFlush(invoker);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
resultRefer.setResult(msg);
countDownLatch.countDown();
}
});
}
});
b.connect(host, port);
countDownLatch.await();
return resultRefer.getResult();
} finally {
group.shutdownGracefully();
}
});
}
}
保存RPC调用结果的类
package ning.zhou.rpc.netty.rpc;
/**
* @author 周宁
* @Date 2019-10-10 18:05
*/
public class ResultRefer {
private Object result;
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
}
测试类HelloService.java和HelloServiceImpl.java
package ning.zhou.rpc.rpc;
/**
* @author 周宁
* @Date 2019-10-09 13:48
*/
public interface HelloService {
String hello(String name);
}
package ning.zhou.rpc.rpc;
/**
* @author 周宁
* @Date 2019-10-09 13:48
*/
public class HelloServiceImpl implements HelloService {
@Override
public String hello(String name) {
return "hello" + name;
}
}
编写服务提供者Provider.java
package ning.zhou.rpc.netty.rpc;
import ning.zhou.rpc.rpc.HelloService;
import ning.zhou.rpc.rpc.HelloServiceImpl;
import java.util.HashMap;
import java.util.Map;
/**
* @author 周宁
* @Date 2019-10-10 16:31
*/
public class Provider {
public static void main(String[] args) {
Export export = new Export();
Map<Class,Object> serv = new HashMap<>();
serv.put(HelloService.class,new HelloServiceImpl());
export.setRegistried(serv);
export.export(1234);
}
}
编写服务消费者Consumer.java
package ning.zhou.rpc.netty.rpc;
import ning.zhou.rpc.rpc.HelloService;
/**
* @author 周宁
* @Date 2019-10-10 17:04
*/
public class Consumer {
public static void main(String[] args) throws InterruptedException {
HelloService helloService = Refer.refer(HelloService.class,"127.0.0.1",1234);
for(int i = 0;i<Integer.MAX_VALUE;i++){
String hello = helloService.hello("World" + i);
System.out.println(hello);
Thread.sleep(1000);
}
}
}
分别启动Provider.java和Consumer.java可以看到控制台有如下输出