远程代理概念
定义
远程代理就是”远程对象的本地代表”。”远程对象”就是一个活在不同JAVA虚拟机(JVM)堆里,即在不同的地址空间中代表同一对象。“”本地代表“就是可以像在本地方法一样调用的对象,其行为转发到远程对象。远程代理就是为了让远程调用看起来跟本地调用对象一样,毫无瑕疵。
结构
这里有四个角色。客户对象,客户代理对象(客户辅助对象),服务辅助对象,服务对象
1.客户对象,就是本队客户端用户,他以为是在跟真正的服务沟通,以为客户代理对象就是真正做事情的对象
2.客户代理对象假装自己就是一个真正的服务,但实际上它只是真东西的一个代理
3.服务辅助对象从客户代理对象取得请求,对它解包,调用真正服务上的方法
4.服务对象才是真正提供服务的地方,他真正在做事
JAVA RMI概述
RMI介绍
JAVA RMI技术就是典型的远程代理案例。
RMI提供了客户辅助对象和服务辅助对象,也为客户辅助对象创建了和服务对象相同的方法。RMI的好处是可以不必写任何网络或I/O代码,就可以让客户程序跟在本地JVM正常调用方法一样调用远程方法(真正的服务所在的方法)。但是虽然调用远程方法跟本地一样,但是客户辅助对象还是需要通过网络发送方法调用的,所以网络和I/O还是存在的。
RMI术语
RMI将客户辅助对象成为stub(桩),把服务辅助对象称为skeleton(骨架)
JAVA RMI实例
制作远程服务
制作远程接口
定义供客户远程调用的服务方法接口。客户对象会把它作为服务的超类,Stub(客户辅助对象)和服务对象都会实现该接口
制作远程的实现类
服务对象,实现远程接口定义的远程方法,也是客户真正想调用的对象,也是真正工作的对象
利用rmic产生的stub和skeleton
rmic是一个工具,用于生成客户辅助对象和服务辅助对象,可以在JDK中找到rmic
启用RMI registry
rmi registry是电话普,客户可以在其中找到客户代理对象(客户辅助对象)的位置,也就是客户的一个Stub helper对象
开始远程服务
让服务对象运行起来,服务实现类回去实例化一个服务实例,然后将这个服务注册到 RMI reigistry,注册后客户就可以调用了
制作远程服务具体实施
制作远程接口
1.接口扩展java.rmi.Remote Remote类是一个记号接口,不包含任何方法,但是是RMI的规范,所以要遵守规则 2.声明的所有方法都抛出RemoteException 客户会调用实现远程接口的stub上的方法,stub底层用到了网络和I/O,可能产生异常 3.要确定变量和返回值都是源于类型或者可序列化类型 远程方法的变量必须被打包并通过网络运输,需要序列化完成。如果是源于类型,字符串和许多API定义的类型(包括数组和集合),都没问题,如果是自定义类,那么要实现Serializable。
最终代码效果
public interface MyRemote extends Remote{
public String getName() throws RemoteException;
}
制作远程实现
1.服务实现类必须实现服务接口 2.服务实现类必须扩展UnicastRemoteObject对象 要成为远程服务对象,对象需要一些远程的功能,由超类为你完成 3.设计无参构造器,抛出RemoteException 这是由于超类UnicastRemoteObject的构造器会抛出异常。那么当服务实现类被实例化,超类构造器会被调用。如果超类构造器抛异常,那么子类也就能抛异常了 4.用RMI Registry注册服务 为了保证被客户对象调用,那么需要服务实例化,然后放进RMI registry。看似绑定服务对象, 但实际上RMI注册的是stub,毕竟registry是关于客户辅助对象的电话本 注册服务使用java.rmi.Naming类的静态方法rebind()
最终代码效果
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
protected MyRemoteImpl() throws RemoteException {
super();
}
@Override
public String getName() throws RemoteException {
return "哈哈哈";
}
}
进行第四步,注册服务是需要保证RMI registry已经启动,你才能注册
注册代码
try {
MyRemote service = new MyRemoteImpl();
Registry registry = LocateRegistry.createRegistry(2500);
registry.bind("myRemote", service);
} catch (Exception e) {
e.printStackTrace();
}
关于rmi的端口默认是1099,这里换成2500
关于如何在eclipse使用RMI registry和RMIC工具,详情见
https://blog.csdn.net/bigtree_3721/article/details/50615702
使用rmic工具产生stub和skeleton
eclipse可以图形化界面生产,具体可以看上面的帖子
启动Rim registry
可以在项目类路径下使用dos命令:rmiregistry启动,但是启动的1099。也可以上图帖子启动
启动服务
可以在创建一个类,作为服务启动类,main方法中放置上面关于注册服务的代码,即可启动
客户端如何使用?
客户端首先需要MyRemote这个接口类,毕竟这是关于服务的类。具体代码如下:
MyRemote myremote = (MyRemote) Naming.lookup("rmi://127.0.0.1:2500/myRemote");
String name = myremote.getName();
System.out.println(name);
Naming.lookup方法返回的是Object,需要强转。
127.0.0.1:2500是指服务的所在ip和端口号。
myRemote是服务类在RMI Registry的注册名,便于客户端找到
客户端运行流程
1.客户到RMI registry中寻找
2.RMI registry返回Stub对象
3.客户调用Stub的方法,就好像Stub是真正的服务对象一样
RMI需要注意的三个点:
1.启动远程服务绑定设备前,要先启动rmiregistry。如果使用Naming.rebind()注册服务的话。如果使用LocateRegistry创建registry的话,那么不需要
2.记得把变量和返回值类型定为可序列化。
3.记得给客户提供stub类,在服务端的时候要用rmic工具创建