标签:rpc
直接用Socket走TCP/IP 或者是UDP协议, 例如RMI
走HTTP协议, Hessian。 好处不用防火墙再开端口了
在下面的例子中,使用java socket。这样可以看到更基础的内容。
句柄部分我们可以使用动态代理,在调用客户端方法的时候使用动态代理来调用远程方法
这个也有很多种,比如Java自带的序列化机制,实现了Serializable接口的类,都能够进行序列化
对于Java序列化的原理可以看下下面的博文:
http://www.java3z.com/cwbwebhome/article/article8/862.html
是Java处理二进制的一贯风格,定义了标志位表示后面有多长的内容表示了一个什么,然后是具体的内容。
Java的反序列化。
最好的办法当然是看ObjectInputStream的源代码了。
大概的流程是:
1. readObject0 入口
2. 然后就是一段一段读取然后解析了。一般最开始读取Class readClass,读取这个类的Class接口
3. readOrdinaryObject 使用newInstance来创建实例
4. 然后用defaultReadFields 中的desc.setObjFieldValues内容来个这个实例的字段赋值。
5. 这是一个循环的过程,知道把对象中所有的内容都还原。
还可以有其他的方式,比如WebService技术是使用了Soap协议来进行传输的,使用的是类似于XML格式的方式描述消息内容的(因此消息内容会比较臃肿)
Hessian是使用了二进制的方式进行了序列化,它使用了自己的规则,该规则可以用其他语言实现,是一个简单而且高效的协议。
细节链接如下:http://hessian.caucho.com/doc/hessian-serialization.html
在下面的例子中使用ObjectInputStream来进行序列化操作。
启动Socket并且给每个请求创建一个处理线程:
public class StartUp { public static final int port = 8080; public static void main(String[] args) { exportRpc(); } /** * 导出RPC接口 */ private static void exportRpc() { try { ServerSocket ss = new ServerSocket(9001); while(true){ Socket s = ss.accept(); new RpcThread(s).start(); } } catch (IOException e) { e.printStackTrace(); } } }
public class RpcObject implements Serializable{ private static final long serialVersionUID = 1L; private Class c; private String methodName; private Object[] args; public RpcObject() { } public RpcObject(Class c, String methodName, Object[] args) { this.c = c; this.methodName = methodName; this.args = args; } public Class getC() { return c; } public void setC(Class c) { this.c = c; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public Object[] getArgs() { return args; } public void setArgs(Object[] args) { this.args = args; } }
public class RpcThread extends Thread { private Socket s; public RpcThread(Socket s) { this.s = s; } @Override public void run() { ObjectInputStream is = null; ObjectOutputStream os = null; try { is = new ObjectInputStream(s.getInputStream()); // 得到远程调用参数,包含了接口名,调用方法,方法参数 RpcObject rpcObject = (RpcObject) is.readObject(); // 构建接口的实现类,然后通过反射调用方法 Object o = getObject(rpcObject.getC()); Object reO = executeMethod(o, rpcObject.getMethodName(), rpcObject.getArgs()); // 输出返回值 os = new ObjectOutputStream(s.getOutputStream()); os.writeObject(reO); os.flush(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { is.close(); os.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 通过反射技术执行方法,并返回返回值 * @param o * @param methodName * @param args * @return */ private Object executeMethod(Object o, String methodName, Object[] args) { Object objR = null; Class[] cs = new Class[args.length]; for (int i = 0; i < args.length; i++) { Object arg = args[i]; cs[i] = arg.getClass(); } try { Method m = o.getClass().getMethod(methodName, cs); objR = m.invoke(o, args); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return objR; } /** * 根据接口名得到实例 * @param c * @return */ private Object getObject(Class c) { Object o = null; try { <span style="white-space:pre"> </span>o = ConfMonitor.conf.get(c.getName()).newInstance(); <span style="white-space:pre"> </span>} catch (InstantiationException e) { <span style="white-space:pre"> </span>e.printStackTrace(); <span style="white-space:pre"> </span>} catch (IllegalAccessException e) { <span style="white-space:pre"> </span>e.printStackTrace(); <span style="white-space:pre"> </span>} return o; } }服务器端配置文件,主要是配置接口对应了哪个实现类:
/** * 模拟配置,实际的框架中大部分都是使用xml进行配置的,比如Hessian是配置在web.xml的servlet属性里的 * @author cdwangzijian * */ public class ConfMonitor { public static Map<String, Class> conf = new HashMap<String, Class>(); static { conf.put("com.prince.rpc.service.IHello", HelloImpl.class); } }
使用动态代理,给每一个方法调用都变为远程调用。
public class ProxyFactory { public static <T> T create(Class<T> c, String ip, int port) { InvocationHandler handler = new RpcProxy(ip, port, c); return (T) Proxy.newProxyInstance(c.getClassLoader(), new Class[] {c }, handler); } }
/** * 客户端接口代理 * 当客户端接口方法被调用的时候,把方法名,方法参数作为参数。 * 传送给远程服务执行,然后获取返回值 * @author cdwangzijian * */ public class RpcProxy implements InvocationHandler, Serializable{ private String ip; private int port; private Class c; private static final long serialVersionUID = 1L; public RpcProxy(String ip, int port, Class c) { this.ip = ip; this.port = port; this.c = c; } /** * 动态代理类,当调用接口方法的时候转为调用此方法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object o = null; // 用作返回值 // 通过socket调用远程服务 Socket s = new Socket(ip, port); // 组装为一个保留了要调用的类,方法名及参数的对象,然后序列化之后传给远程 RpcObject rpcObject = new RpcObject(c, method.getName(), args); ObjectOutputStream os = null; ObjectInputStream is = null; try{ os = new ObjectOutputStream(s.getOutputStream()); os.writeObject(rpcObject); os.flush(); // 从远程得到返回结果 is = new ObjectInputStream(s.getInputStream()); o = is.readObject(); } catch (Exception e) { e.printStackTrace(); } finally{ os.close(); is.close(); } return o; } }最后是调用部分,获得代理类。
public class RpcClient { public static void main(String[] args) { String ip = "localhost"; int port = 9001; IHello hello = ProxyFactory.create(IHello.class, ip, port); System.out.println(hello.sayHello("wzj")); } }
public interface IHello { String sayHello(String name); }
public class HelloImpl implements IHello { @Override public String sayHello(String name) { return "hello:" + name; } }
http://download.csdn.net/detail/three_man/8059871
标签:rpc
原文地址:http://blog.csdn.net/three_man/article/details/40296909