之前看到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);
}