(1)确定变量和返回值是属于原语(primitive)类型或者可序列化的(Seriailizable)类型。原语类型 都实现了Seriailizable接口。
(2)transient 关键字,告诉JVM不要序列化这个字段。
动态类下载(dynamic class downloading )
代理模式 :控制对象的访问
代理模式有很多种。如:远程代理,虚拟代理。动态代理(保护代理)
客户调用本地的方法,本地的方法调用远程的方法。 本地方法就是“代理”。“代理”处理所有网络通信的低层细节。
Java 内置远程调用功能:RMI
RMI的好处:
不必写任何网络或I/O代码。
客户程序调用远程方法(即真正的服务所在)就和在运行本地JVM上对象进行正常方法调用一样。
lookup service 这个服务用来寻找和访问远程对象。
注意:I/O 和网络 是有网险的,容易失败,所以必须随时抛出异常。
---------------------远程调用实现步骤---------------------
RMI 会产生客户端辅助对象(称为stub(桩)命名格式类名_Stub.class)和服务端辅助对象(称为skeleton(骨架)命名格式类名_Skel.class)。
一、制作远程服务(远程端)
(1)制作远程接口。 接口定义了让客户远程调用的方法。
1.扩展java.rmi.Remote Remote是一个"记号“接口,不具有方法,对于RMI来说Remote具有特别的意义。
public interface MyRemote extends Remote{} //表示此接口用来扶持远程调用
2.声明所有方法都抛出RemoteException.
<span style="white-space:pre"> </span>import java.rmi.*;
<span style="white-space:pre"> </span>public interface MyRemote extends Remote{
<span style="white-space:pre"> </span>public String sayHello() throws RemoteException;
<span style="white-space:pre"> </span>}
3.确定变量和返回值属于原语(primitive)类型或者可序列化(Serializable)类型
远程方法的变量必须被打包并通过网络运送,这要靠序列化来完成。
(2)制作远程接口实现。
1.public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
//sayHello的实现
}
2.扩展UnicastRemoteOject .为了成为远程服务对象,你的对象需要某些”远程的“功能,最简单的方式实现此类。
3.设计一个不带变量的构造器,并声明RemoteException
<span style="white-space:pre"> </span>/**
<span style="white-space:pre"> </span>新超类UnicassRemoteObject带来一个小问题:它的构造器抛出RemoteException.唯一解决这个问题的方法就是此类也声明此异常。
<span style="white-space:pre"> </span>如果超类的构造器抛出异常,那么子类的构造器也必须抛出异常。
<span style="white-space:pre"> </span>由于调用子类构造的时候先调用父类的构造,所以父类抛出的异常要小于等于子类抛出的异常
<span style="white-space:pre"> </span>*/
<span style="white-space:pre"> </span>public MyRemoteImpl() throws RemoteException
4.用RMI Registry注册此服务。 放在mian()方法中。 等价于第5步。
<span style="white-space:pre"> </span>让它可以被远程客户调用,将此服务实例化,然后放进RMI registry中(记得先确定rmi registry 正在运行,否则注册会失败)。当注册这个对象时,RMI系统其实注<span style="white-space:pre"> </span>册的是stub,因为这是客户真正需要的。注册服务使用java.rmi.Naming类的静态rebind()方法。
<span style="white-space:pre"> </span>try{
<span style="white-space:pre"> </span>MyRemote service = new MyRemoteImpl();
<span style="white-space:pre"> </span>Naming.rebind("RemoteHello",service); //为服务命名,好让客户在注册表中寻找。
<span style="white-space:pre"> </span>}catch(Exception ex){...}
(3)利用rmic产生stub和skeleton。 JDK中有此工具 %rmic MyRemoteIMpl
在远程实现类上执行rmic
(4)启动RMI regisgry(rmiregistry). rmiregisty就像电话簿,客户可以从中查到代理的位置。 %rmiregistry --开启一个终端,启动rmiregistry 确定启动目录必须可以访问你的类。“classes”目录启动。
(5)开启远程服务 %java MyServiceImpl
二、客户端如何得到Stub对象。
客户必须取得stub对象(我们的代理)以调用其中的方法。所以我们需要RMI Registry的帮忙。客户从Registry中寻找(lookup)代理。
MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteHello"); //"RemoteHello" 远程端注册时使用的名字。
三、工作方式。
(1)客户到registry中寻找。Naming.lookup("rmi://127.0.0.1/RemoteHello");
(2)RMI registry 返回stub对象。 (作为lookup方法的返回值)然后RMI会自动对stub反序列化。你在客户端必须有stub类(由rmic)为你产生,否则stub就无法被反序列化。
(3)调用stub的方法,就像stub就是真正的服务对象一样。
客户端完整代码
import java.rmi.Naming;
public class MyRemoteClient {
public static void main(String[] args) {
new MyRemoteClient().go();
}
public void go(){
try{
MyRemote service = (MyRemote)Naming.lookup("rmi://127.0.0.1/RemoteHello");
String s = service.sayHello();
System.out.println(s);
}catch(Exception e){
e.getMessage();
}
}
}
需要注意的是 注册服务前 需要开启一个命令窗口执行 rmiregstry 命令 此命令在 看得见 远程类的路径下执行。
远程接口完完整代码
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyRemote extends Remote{
public String sayHello() throws RemoteException;
}
远程实现完整代码
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
@Override
public String sayHello() throws RemoteException {
return "Server says ";
}
public MyRemoteImpl() throws RemoteException{}
public static void main(String[] args) {
try {
MyRemote service = new MyRemoteImpl();
Naming.rebind("RemoteHello", service);
} catch (Exception e) {
e.printStackTrace();
System.out.println("111");
}
}
}
对于RMI 程序员常犯的三个错误:
1.忘了在启动远程服务之前先启动rmiregistry (要用Naming.rebind()注册服务,rmiregistry必须是运行的)
2.忘了让变量和返回值的类型成为可序列化的类型(这种错误无法在编译期发现,只会在运行时发现)。
3.忘了给客户提供stub类。