自定义rpc服务

之前看到dubbo开发成员写的一篇博客,实现一个简单的rpc框架,觉得挺有意思的,按照他的思路,照样写了一个供学习参考。具体的java代码如下:

public class RpcServer {
	public static void export(final Object service, int port) throws Exception {
		if (service == null) {
			throw new IllegalArgumentException("service instance == null");
		}
		
		if (port <= 0 || port > 65535) {
			throw new IllegalArgumentException("Invalid port " + port);
		}
		
		System.out.println("Export service " + service.getClass().getName() + " on port " + port); 
		
		ServerSocket server = new ServerSocket(port);
		for (;;) {
			try {
				final Socket socket = server.accept();
				new Thread(new Runnable() {
					public void run() {
						ObjectOutputStream output = null;
						ObjectInputStream input = null;
						try {
							input = new ObjectInputStream(socket.getInputStream());
							String methodName = input.readUTF();
							Class<?>[] parameterTypes = (Class<?>[])input.readObject();
							Object[] arguments = (Object[])input.readObject();
							
							output = new ObjectOutputStream(socket.getOutputStream());

							Method m = service.getClass().getMethod(methodName, parameterTypes);
							
							String ret = (String) m.invoke(service, arguments);
							output.writeObject(ret);
							
						} catch (Exception e) {
							e.printStackTrace();
						} finally {
							try {
								input.close();
								output.close();
								socket.close();
							} catch (Exception e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					}
				}).start();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T refer(final Class<T> interfaceClass, final String host, final int port) throws Exception {
		if (null == interfaceClass) {
			throw new IllegalArgumentException("interfaceClass class == null");
		}
		if (!interfaceClass.isInterface()) {
			throw new IllegalArgumentException("The " + interfaceClass.getName() + " must be interface class!");
		}
		if (host == null || host.length() == 0) {  
            throw new IllegalArgumentException("Host == null!");
		}
		if (port <= 0 || port > 65535) { 
            throw new IllegalArgumentException("Invalid port " + port); 
		}
		System.out.println("Get remote service " + interfaceClass.getName() + " from server " + host + ":" + port);
		
		return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), 
				new Class<?>[]{interfaceClass}, new InvocationHandler() {

				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					Socket socket = new Socket(host, port);
					ObjectOutputStream output = null;
					ObjectInputStream input = null;
					try {
						output = new ObjectOutputStream(socket.getOutputStream());
						output.writeUTF(method.getName());
						output.writeObject(method.getParameterTypes());
						output.writeObject(args);
						
						input = new ObjectInputStream(socket.getInputStream());
						Object result = input.readObject();  
                        if (result instanceof Throwable) {  
                            throw (Throwable) result;  
                        }  
                        return result;
                        
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						output.close();
						input.close();
						socket.close();
					}
					return null;
				}
		});
	}
}
整个实现思路比较简单,就是socket对象传输+反射+动态代理。

其中暴露服务的过程,实际上就是建立一个socketserver的监听,然后读取传递过来的对象信息,如方法名,参数类型,参数值,其中方法名和参数类型,用于确定调用方法,然后调用invoke方法,需要服务对象和参数值,然后将方法执行的返回值利用输出流对象输出。

ITestService service = new TestServiceImpl();  
        RpcServer.export(service, 12345);  

另外引用服务的过程,实际上是返回一个代理对象的过程,并且采用匿名的handler类对象,invoke方法用来建立和服务端的socket连接,然后基于对象输出流,输入方法信息,比如方法名,参数类型,参数值,然后再等待服务端的返回。(这里可以看出服务的引用方实际上只需要接口的定义类就可以了。)

ITestService service = RpcServer.refer(ITestService.class, "127.0.0.1", 1234);  
        for (int i = 0; i < 10; i ++) {  
            String hello = service.hello("World" + i);  
            System.out.println(hello);  
            Thread.sleep(1000);  
        }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值