简单的说就是有一个远程服务和若干台监视器,监视器用来监视远程服务中的有关数据。监视任务的
障碍点在于远程服务和监视器程序不在同一个JVM上。这就导致监视器没法在本地直接调用服务器的
方法对其进行监控。我们需要一个代理来,监视器所做的就像是在做远程方法调用,但其实只是调用
本地堆中的"代理"对象上的方法,再由代理处理所有网络通信的低层细节。
制作远程服务的步骤:
1:制作远程接口,接口定义了要供客户调用的远程方法。
MyRemote.java : interface MyRemote extends Remote (接口继承接口)
2.制作远程的实现,这就是客户想要真正调用的方法。
MyRemoteImpl.java : class MyRemoteImpl extends UnicastRemoteObject implements Remote (
UnicastRemostObject让超类帮助子类成为远程对象,具备某些”远程“功能)
//3.设计一个不带变量的构造器,并声明RemoteException。因为如果超类的构造器抛出异常,那么你只能声明
子类的构造器也抛出异常。这个比编译器会检查到错误并给出提示。
public MyRemoteImpl() throws RemoteException{}
3.利用rmic产生的stub和skeleton。
% rmic MyRemoteImpl ,
就会产生两个新的类,作为辅助对象 : MyRemoteImpl_Stub.class和MyRemoteImpl_Skel.class
4.用RMI Registry注册此服务
% rmiregistry
5.开始远程服务。
%java MyRemoteImpl
远程服务实现代码如下:
MyRemote接口:
public interface MyRemote extends Remote{
public String sayHello() throws RemoteException;
}
MyRemoteImple服务类:
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
protected MyRemoteImpl() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
@Override
public String sayHello() throws RemoteException {
// TODO Auto-generated method stub
return "Server says, ‘Hey‘";
}
public static void main(String [] args)
{
try {
MyRemote service=new MyRemoteImpl();
Naming.rebind("RemoteHello", service);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
再看客户对象的工作方式:
1.客户到RMI registry中寻找。
Naming.lookup("rmi://127.0.0.1/RemoteHello");
2.RMI Registry返回Stub对象,然后RMI会自动对stub反序列化。你在客户端必须有stub类,
否则stub就无法被反序列化。
3.客户调用stub方法,就像stub就是真正的服务对象一样。
完整的客户端代码:
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 ex)
{
ex.printStackTrace();
}
}
}
编译过程如下图所示:
生成stub和skeleton,并启动RMI registry。rmiregistry 就像电话簿,客户可以从中查到代理的位置(也就是客户的stub helper对象)。
启动远程服务:
然后将编译时服务端生成的相应的.class文件包括stub的class文件复制到客户端类文件夹下。再对客户端类
进行编译运行。如下图所示:
到此位置,我们的任圆满完成。
在实现这个过程中遇到些阻碍,在这篇博客结束前针对于实现的过程做一下总结:
1.在利用rmic产生stub和skeleton类的过程中,找不到类。最后解决方法:set classpath=编译产生
的远程服务的class文件的路径。其中还要注意类所在的包的问题。
2.rmic只针对于远程服务创建stub和skeleton。如果针对于非远程服务将会出现如下报错:
3.在编译客户代码前,首先要把远程服务中相应的class文件以及stub类放入客户端类文件下。
4.在编译客户代码类时先要设置classpath变量:set classpath="客户代码类所在的路径"
5.在客户和远程服务至今传送的变量和返回值类型必须是可序列化的类型。因为只有是可序列化的,才可以通过
网络对变量和返回值进行打包并传送。
代理模式第一篇