直接用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 {
o = ConfMonitor.conf.get(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return o;
}
}
服务器端配置文件,主要是配置接口对应了哪个实现类:
/**
* 模拟配置,实际的框架中大部分都是使用xml进行配置的,比如Hessian是配置在web.xml的servlet属性里的
* @author cdwangzijian
*
*/
public class ConfMonitor {
public static Map conf = new HashMap();
static {
conf.put("com.prince.rpc.service.IHello", HelloImpl.class);
}
}
使用动态代理,给每一个方法调用都变为远程调用。
public class ProxyFactory {
public static T create(Class 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