文章目录
- 一、RPC基本介绍
- 二、服务端
- 1、定义接口及实现类
- 2、定义服务端与客户端传输类
- 3、服务端启动类
- 4、服务端处理类
- 三、客户端
- 1、客户端代理类
- 2、客户端处理类
- 3、测试类
一、RPC基本介绍
RPC(Remote Procedure Call) —— 远程过程调用,是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。
两个或多个应用都分布在不同的服务器上,它们之间的调用就像是本地方法调用一样:
二、服务端
1、定义接口及实现类
public interface IRpcService {
//加
int add(int a,int b);
//减
int sub(int a,int b);
//乘
int mult(int a,int b);
//除
int div(int a ,int b);
}
public interface IRpcHelloService {
String hello(String name);
}
public class RpcHelloServiceImpl implements IRpcHelloService {
public String hello(String name) {
return "hello " + name + "!";
}
}
public class RpcServiceImpl implements IRpcService {
public int add(int a, int b) {
return a + b;
}
public int sub(int a, int b) {
return a - b;
}
public int mult(int a, int b) {
return a * b;
}
public int div(int a, int b) {
return a / b;
}
}
2、定义服务端与客户端传输类
@Data
public class InvokerProtocol implements Serializable {
private String className; //类名
private String methodName; //方法名称
private Class<?>[] params; //形参列表
private Object[] values; //实参列表
}
3、服务端启动类
public class RpcRegistry {
private int port;
public RpcRegistry(int port) {
this.port = port;
}
private void start() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
//扫描所有需要注册的类
RegistryHandler.scannerClass("com.netty.rpc.provider");
//将扫描到的类注册到一个容器中
RegistryHandler.doRegister();
try {
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) throws Exception {
//接收课客户端请求的处理流程
ChannelPipeline pipeline = ch.pipeline();
int fieldLength = 4;
//通用解码器设置
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,fieldLength,0,fieldLength));
//通用编码器
pipeline.addLast(new LengthFieldPrepender(fieldLength));
//对象编码器
pipeline.addLast("encoder",new ObjectEncoder());
//对象解码器
pipeline.addLast("decoder",new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new RegistryHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = server.bind(this.port).sync();
System.out.println("RPC registry is start,listen at " + this.port);
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
new RpcRegistry(8080).start();
}
}
4、服务端处理类
public class RegistryHandler extends ChannelInboundHandlerAdapter {
//注册中心容器
private static ConcurrentHashMap<String,Object> registryMap = new ConcurrentHashMap<String, Object>();
private static List<String> classNames = new ArrayList<String>();
public RegistryHandler(){
}
public static void doRegister() {
if(classNames.size() == 0){return;}
for (String className : classNames) {
try {
Class<?> clazz = Class.forName(className);
Class<?> i = clazz.getInterfaces()[0];
registryMap.put(i.getName(),clazz.newInstance());
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void scannerClass(String packageName) {
URL url = RegistryHandler.class.getClassLoader().getResource(packageName.replaceAll("\\.","/"));
File dir = new File(url.getFile());
for (File file : dir.listFiles()) {
//如果是文件夹,继续递归
if(file.isDirectory()){
scannerClass(packageName + "." + file.getName());
}else {
classNames.add(packageName + "." + file.getName().replace(".class","").trim());
}
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Object result = new Object();
InvokerProtocol request = (InvokerProtocol) msg;
System.out.println("服务端收到消息");
if(registryMap.containsKey(request.getClassName())){
//用反射直接调用Provider的方法
Object provider = registryMap.get(request.getClassName());
Method method = provider.getClass().getMethod(request.getMethodName(),request.getParams());
result = method.invoke(provider,request.getValues());
}
ctx.write(result);
ctx.flush();
ctx.close();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
三、客户端
1、客户端代理类
public class RpcProxy {
public static <T> T create(Class<?> clazz){
MethodProxy proxy = new MethodProxy(clazz);
Class<?> [] interfaces = clazz.isInterface() ?
new Class[]{clazz} :
clazz.getInterfaces();
T result = (T)Proxy.newProxyInstance(clazz.getClassLoader(),interfaces,proxy);
return result;
}
public static class MethodProxy implements InvocationHandler {
private Class<?> clazz;
public MethodProxy(Class<?> clazz) {
this.clazz = clazz;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(Object.class.equals(method.getDeclaringClass())){
return method.invoke(this,args);
}else{
return rpcInvoke(proxy,method,args);
}
}
private Object rpcInvoke(Object proxy, Method method, Object[] args) {
//封装请求的内容
InvokerProtocol msg = new InvokerProtocol();
msg.setClassName(this.clazz.getName());
msg.setMethodName(method.getName());
msg.setParams(method.getParameterTypes());
msg.setValues(args);
final RpcProxyHandler consumerHandler = new RpcProxyHandler();
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap client = new Bootstrap();
client.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) throws Exception {
//接收课客户端请求的处理流程
ChannelPipeline pipeline = ch.pipeline();
int fieldLength = 4;
//通用解码器设置
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,fieldLength,0,fieldLength));
//通用编码器
pipeline.addLast(new LengthFieldPrepender(fieldLength));
//对象编码器
pipeline.addLast("encoder",new ObjectEncoder());
//对象解码器
pipeline.addLast("decoder",new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
pipeline.addLast("handler",consumerHandler);
}
})
.option(ChannelOption.TCP_NODELAY, true);
ChannelFuture future = client.connect("localhost",8080).sync();
future.channel().writeAndFlush(msg).sync();
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
group.shutdownGracefully();
}
return consumerHandler.getResponse();
}
}
}
2、客户端处理类
public class RpcProxyHandler extends ChannelInboundHandlerAdapter {
private Object response;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
this.response = msg;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
public Object getResponse() {
return this.response;
}
}
3、测试类
public class RpcConsumer {
public static void main(String[] args) {
IRpcHelloService rpcHello = RpcProxy.create(IRpcHelloService.class);
System.out.println(rpcHello.hello("Tom"));
IRpcService rpc = RpcProxy.create(IRpcService.class);
System.out.println("8 + 2 = " + rpc.add(8,2));
System.out.println("8 - 2 = " + rpc.sub(8,2));
System.out.println("8 * 2 = " + rpc.mult(8,2));
System.out.println("8 / 2 = " + rpc.div(8,2));
}
}