基于Netty的RPC简单框架实现(二):RPC服务端
来源:互联网 发布:sql like 编辑:程序博客网 时间:2024/05/01 13:21
1.RPC服务端的实现思路
相对于客户端而言,服务端要简单不少。基本思想就是,创建RPC服务端的时候,创建一个RPC请求队列和一定数量的Handler线程。Handler线程都持有服务端提供服务的Interface的类类型和实际供方法调用的对象(实现了提供服务的Interface),各线程只需要不断从RPC请求队列中取出请求,然后用供方法调用的对象来调用所请求的方法,最后将调用的结果通过Netty发送回客户端即可。
2.RPC服务端的具体实现
(1).RpcRequest
在具体实现RPC服务端之前,先定义RpcRequest类。
package com.maigo.rpc.context;public class RpcRequest {int id;String methodName;Object[] args;public RpcRequest(int id, String methodName, Object[] args) {this.id = id;this.methodName = methodName;this.args = args;}public int getId() {return id;}public String getMethodName() {return methodName;}public Object[] getArgs() {return args;}}RpcRequest表示了一个RPC调用请求。id用于区分多次不同的调用,methodName为请求调用的方法名,args为参数。
(2).RpcServerBuilder
RpcServerBuilder是创建RpcServer的工厂类
package com.maigo.rpc.server;import com.maigo.rpc.aop.RpcInvokeHook;public class RpcServerBuilder {private Class<?> interfaceClass;private Object serviceProvider;private int port;private int threads;private RpcInvokeHook rpcInvokeHook;public static RpcServerBuilder create(){return new RpcServerBuilder();}/** * set the interface to provide service * @param interfaceClass */public RpcServerBuilder serviceInterface(Class<?> interfaceClass){this.interfaceClass = interfaceClass;return this;}/** * set the real object to provide service */public RpcServerBuilder serviceProvider(Object serviceProvider){this.serviceProvider = serviceProvider;return this;}/** * set the port to bind */public RpcServerBuilder bind(int port){this.port = port;return this;}/** * set the count of threads to handle request from client. (default availableProcessors) */public RpcServerBuilder threads(int threadCount){this.threads = threadCount;return this;}/** * set the hook of the method invoke in server */public RpcServerBuilder hook(RpcInvokeHook rpcInvokeHook){this.rpcInvokeHook = rpcInvokeHook;return this;}public RpcServer build(){if(threads <= 0)threads = Runtime.getRuntime().availableProcessors();RpcServer rpcServer = new RpcServer(interfaceClass, serviceProvider, port, threads, rpcInvokeHook);return rpcServer;}}API都很简单,create()创建工场,serviceInterface()设置服务接口,serviceProvider()设置供方法调用的实际对象,bind()设置绑定的端口号,threads()设置Handler线程的个数(默认为CPU核数),build()创建出RpcServer对象。
(3).RpcServer
package com.maigo.rpc.server;import java.util.concurrent.atomic.AtomicInteger;import com.maigo.rpc.aop.RpcInvokeHook;import com.maigo.rpc.context.RpcRequest;public class RpcServer {private Class<?> interfaceClass;private Object serviceProvider;private int port;private int threads;private RpcInvokeHook rpcInvokeHook;private RpcServerRequestHandler rpcServerRequestHandler;protected RpcServer(Class<?> interfaceClass, Object serviceProvider, int port, int threads,RpcInvokeHook rpcInvokeHook) {this.interfaceClass = interfaceClass;this.serviceProvider = serviceProvider;this.port = port;this.threads = threads;this.rpcInvokeHook = rpcInvokeHook;rpcServerRequestHandler = new RpcServerRequestHandler(interfaceClass, serviceProvider, threads, rpcInvokeHook);rpcServerRequestHandler.start();}public void start(){System.out.println("bind port:"+port + " success!");//simulation for receive RpcRequestAtomicInteger idGenerator = new AtomicInteger(0);for(int i=0; i<10; i++){rpcServerRequestHandler.addRequest(new RpcRequest(idGenerator.addAndGet(1), "testMethod01", new Object[]{"qwerty"}));}}public void stop(){//TODO add stop codes hereSystem.out.println("server stop success!");}}RpcServer只提供了start()和stop()方法用于启动和停止RPC服务。由于启动和停止要涉及网络部分,现在先用打印输出代替。start()方法中还模拟了收到RpcRequest的情况,用于当前无网络连接的情况下测试。RpcServer的构造方法中创建了一个RpcServerRequestHandler,专门用于处理RpcRequest。
(4).RpcServerRequestHandler
专门用于处理RpcRequest的类
package com.maigo.rpc.server;import java.util.concurrent.BlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingQueue;import com.maigo.rpc.aop.RpcInvokeHook;import com.maigo.rpc.context.RpcRequest;public class RpcServerRequestHandler {private Class<?> interfaceClass;private Object serviceProvider;private RpcInvokeHook rpcInvokeHook;private int threads;private ExecutorService threadPool;private BlockingQueue<RpcRequest> requestQueue = new LinkedBlockingQueue<RpcRequest>();public RpcServerRequestHandler(Class<?> interfaceClass,Object serviceProvider, int threads,RpcInvokeHook rpcInvokeHook) {this.interfaceClass = interfaceClass;this.serviceProvider = serviceProvider;this.threads = threads;this.rpcInvokeHook = rpcInvokeHook;}public void start(){threadPool = Executors.newFixedThreadPool(threads);for(int i=0; i<threads; i++){threadPool.execute(new RpcServerRequestHandleRunnable(interfaceClass, serviceProvider, rpcInvokeHook, requestQueue));}}public void addRequest(RpcRequest rpcRequest){try {requestQueue.put(rpcRequest);} catch (InterruptedException e) {e.printStackTrace();}}}在RpcServerRequestHandler的构造方法中,创建了1个大小为threads的线程池,并让其运行了threads个RpcServerRequestHandleRunnable。每个RpcServerRequestHandleRunnable持有相同的服务接口interfaceClass表示服务端提供哪些服务,相同的服务提供对象serviceProvider供实际方法调用,相同的请求队列requestQueue用于取出收到的方法调用请求。
(5).RpcServerRequestHandleRunnable
方法调用请求的实际执行者
package com.maigo.rpc.server;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.concurrent.BlockingQueue;import com.maigo.rpc.aop.RpcInvokeHook;import com.maigo.rpc.context.RpcRequest;public class RpcServerRequestHandleRunnable implements Runnable{private Class<?> interfaceClass;private Object serviceProvider;private RpcInvokeHook rpcInvokeHook;private BlockingQueue<RpcRequest> requestQueue;public RpcServerRequestHandleRunnable(Class<?> interfaceClass,Object serviceProvider, RpcInvokeHook rpcInvokeHook, BlockingQueue<RpcRequest> requestQueue) {this.interfaceClass = interfaceClass;this.serviceProvider = serviceProvider;this.rpcInvokeHook = rpcInvokeHook;this.requestQueue = requestQueue;}public void run() {while(true){try {RpcRequest rpcRequest = requestQueue.take();String methodName = rpcRequest.getMethodName();Object[] args = rpcRequest.getArgs();int parameterCount = args.length;Method method = null;if(parameterCount > 0){Class<?>[] parameterTypes = new Class[args.length];for(int i=0; i<parameterCount; i++){parameterTypes[i] = args[i].getClass();}method = interfaceClass.getMethod(methodName, parameterTypes);}else{method = interfaceClass.getMethod(methodName);}if(rpcInvokeHook != null)rpcInvokeHook.beforeInvoke(methodName, args);Object result = method.invoke(serviceProvider, args);System.out.println("Send response id = " + rpcRequest.getId() + " result = " + result + " back to client. " + Thread.currentThread());if(rpcInvokeHook != null)rpcInvokeHook.afterInvoke(methodName, args);} catch (InterruptedException e) {e.printStackTrace();} catch (NoSuchMethodException e) {// TODO return NoSuchMethodException to cliente.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalAccessException e) {// TODO return IllegalAccessException to cliente.printStackTrace();} catch (IllegalArgumentException e) {// TODO return IllegalArgumentException to cliente.printStackTrace();} catch (InvocationTargetException e) {// TODO return Exception to cliente.printStackTrace();}}}}RpcServerRequestHandleRunnable不断地从请求队列requestQueue中取出方法调用请求RpcRequest,用serviceProvider调用请求的方法并向客户端返回调用结果。由于现在还未加入网络部分,向客户端返回结果暂时先用打印输出代替。在方法实际调用的前后,钩子Hook的回调得到了执行。
3.测试
RpcServer中的start()方法模拟了收到10个调用请求的情况
TestInterface testInterface = new TestInterface() {public String testMethod01(String string) {return string.toUpperCase();}};RpcInvokeHook hook = new RpcInvokeHook() {public void beforeInvoke(String methodName, Object[] args) {System.out.println("beforeInvoke " + methodName);}public void afterInvoke(String methodName, Object[] args) {System.out.println("afterInvoke " + methodName);}};RpcServer rpcServer = RpcServerBuilder.create() .serviceInterface(TestInterface.class) .serviceProvider(testInterface) .threads(4) .hook(hook) .bind(3721) .build();rpcServer.start();
bind port:3721 success!beforeInvoke testMethod01beforeInvoke testMethod01beforeInvoke testMethod01beforeInvoke testMethod01Send response id = 2 result = QWERTY back to client. Thread[pool-1-thread-2,5,main]Send response id = 4 result = QWERTY back to client. Thread[pool-1-thread-4,5,main]Send response id = 1 result = QWERTY back to client. Thread[pool-1-thread-1,5,main]Send response id = 3 result = QWERTY back to client. Thread[pool-1-thread-3,5,main]afterInvoke testMethod01afterInvoke testMethod01afterInvoke testMethod01beforeInvoke testMethod01beforeInvoke testMethod01afterInvoke testMethod01Send response id = 5 result = QWERTY back to client. Thread[pool-1-thread-1,5,main]Send response id = 6 result = QWERTY back to client. Thread[pool-1-thread-4,5,main]beforeInvoke testMethod01afterInvoke testMethod01beforeInvoke testMethod01afterInvoke testMethod01beforeInvoke testMethod01beforeInvoke testMethod01Send response id = 10 result = QWERTY back to client. Thread[pool-1-thread-1,5,main]afterInvoke testMethod01Send response id = 9 result = QWERTY back to client. Thread[pool-1-thread-4,5,main]afterInvoke testMethod01Send response id = 7 result = QWERTY back to client. Thread[pool-1-thread-2,5,main]afterInvoke testMethod01Send response id = 8 result = QWERTY back to client. Thread[pool-1-thread-3,5,main]afterInvoke testMethod01可见,共有4个Handler线程在工作,并且都正确的调用了被请求的方法,设置的Hook也受到了正确的回调。
0 0
- 基于Netty的RPC简单框架实现(二):RPC服务端
- 基于Netty的RPC简单框架实现(一):RPC客户端
- 自定义基于netty的rpc框架(2)---服务端的实现
- 基于Netty的RPC简单框架实现(四):Netty实现网络传输
- 基于Netty的RPC简单框架实现(三):Kryo实现序列化
- 基于netty的rpc框架
- 基于Netty的RPC简单框架实现(五):功能测试与性能测试
- 基于Netty和Zookeeper实现RPC框架
- RPC服务框架(二) 简单RPC实现
- 基于hessian和netty的RPC框架设计和实现
- 基于hessian和netty的RPC框架设计和实现
- Netty实现简单RPC
- 基于Netty的分布式 RPC 框架
- 自定义基于netty的rpc框架(1)
- 使用Akka实现一个简单的RPC框架(二)
- 自定义基于netty的rpc框架(3)---客户端的实现
- 自定义基于netty的rpc框架(4)---zk和utils以及protocol的实现
- netty实现高性能的rpc框架
- FRAMEBUFFER 显示原理及RGB显示
- 衡阳哪个微信公众号最好?
- JavaScript基础回顾
- 机器学习实战2:k近邻算法KNN(python)
- 【NOIP2013-D1T3】货车运输
- 基于Netty的RPC简单框架实现(二):RPC服务端
- 63行代码实现贪吃蛇
- synchronized 与 lock
- 动态内存分配
- MyEclipse+MySQL+SQLyog的使用心得
- 在Ubuntu 12.04安装和设置SSH服务
- 掌握内部类
- 《剑指offer》斐波那契数列
- 使用注册表表去掉win7桌面图标箭头的方法