Java RMI (1)

1. Java RMI
Java Remote Method Invocation(Java远程方法调用)允许程序员创建分布式Java技术为基础的应用,可以调用不同JVM远程对象上的远程方法。RMI使用对象序列化去marshal(编码),unmarshal(解码)参数进行,不截断类型,支持面向对象的多态性。

2. Stub
[img]http://dl.iteye.com/upload/attachment/452590/a2f57c28-6c2d-311f-9026-a499d21b6b75.jpg[/img]

RMI相当于一个代理模式。客户对象想要调用远程服务对象上的远程方法,我们需要一些辅助对象。这些辅助的对象使客户就像在调用本地对象的方法一样。客户对象调用客户辅助对象上的方法,仿佛客户辅助对象就是真正的服务。而客户辅助对象负责为我们转发这些请求,但是客户辅助对象不是真正的远程服务。虽然操作很像,但是不具有真正远程服务对象的方法逻辑。在服务端,服务辅助对象从客户辅助对象中接受请求,将调用的信息解包,然后调用真正服务对象上的真正方法。服务辅助对象从服务中得到返回值,将它打包,然后返回客户辅助对象,客户服务对象对信息解包,最后将返回值交给客户端。
Stub(存根)就相当于这里的客户辅助对象。存根将所需要的参数进行编码后传递给远程方法,并将调用结果或者异常传递给客户端。从JDK1.5开始,存根类可以采用动态代理的方式自动生成。在这之前,必须使用rmic工具手动创建。

3. java.rmi.Remote
3.1 扩展java.rmi.Remote接口
Remote是一个标记接口,没有任何方法,所有远程服务对象必须间接或者直接的扩展Remote接口。由于远程服务对象可以被其他的JVM调用,所有可以实现一个或多个远程接口。如果远程服务对象被同时的访问,必须在其实现中保证线程的安全。

public interface MyRemote extends java.rmi.Remote{}

3.2 接口声明中的所有方法都将抛出RemoteException异常。
客户调用远程接口的stub上的方法,而stub底层调用了网络和I/O,所以可能会发生各种异常,所以必须声明远程异常来解决。java.rmi.RemoteException继承自java.io.IOException。

public interface MyRemote extends Remote{
public String sayHello() throws RemoteException;
}

3.3 远程方法的变量和返回值必须是原语类型或者是可序列化类型。
这不难理解,因为远程方法的变量必须被打包并通过网络发送。(所以,在传送自己定义的类时,必须保证实现Serializable接口)

4. java.rmi.RemoteException
RemoteException继承自java.io.IOException。它是一个检查型异常,通常用来标识:通信失败、远程调用参数/返回值在编码(marshalling)/解码(unmarshalling)过程中出错,协议错误。

5. java.rmi.server.RemoteObject
[img]http://dl.iteye.com/upload/attachment/452596/9cbbe9f2-ad8b-3fdf-9e35-cf7c3c28c4f7.jpg[/img]

RemoteObject类实现远程对象的java.lang.Object 行为,并提供了远程对象默认的hashCode、equals 和 toString 方法实现。创建远程对象并将其导出(使远程对象具有某些"远程的"功能)所需的方法由类UnicastRemoteObject 和 Activatable 提供。

6. java.rmi.registry.Registry
Registry是简单远程对象注册表的一个远程接口(默认的端口号为1099
),它提供绑定和查找的功能。其内部维护了一个名到对象的映射。LocateRegistry 用于获得对特定主机(包括本地主机)上引导远程对象注册表的引用,或用于创建一个接受对特定端口调用的远程对象注册表。 注意,getRegistry 调用并不实际生成到远程主机的连接。它只创建对远程注册表的本地引用,即便远程主机上没有正运行的注册表,它也会成功创建一个引用。LocateRegistry.createRegistry()方法在本机指定的端口上创建并发布一个registry远程对象。

7. 示例程序:
7.1 定义远程接口

public interface MyRemote extends Remote {
public String sayHello() throws RemoteException;
}

7.2 实现远程接口

public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{

private static final long serialVersionUID = -3510887331988311760L;

protected MyRemoteImpl() throws RemoteException {
} //这里必须抛出RemoteException异常,因为超类会抛出这个异常

@Override
public String sayHello() throws RemoteException {
return "server say hello to client";
}
}


7.3 用RMI Registry注册此服务

public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{

private static final long serialVersionUID = -3510887331988311760L;

protected MyRemoteImpl() throws RemoteException {
}

@Override
public String sayHello() throws RemoteException {
return "server say hello to client";
}

public static void main(String[] args) {
try {
MyRemote remote = new MyRemoteImpl();
Naming.bind("myRemoteServer", remote);
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
e.printStackTrace();
}

}
}

当注册这个实现对象时,RMI系统实际注册的是stub。

7.4 客户端定义

public class Client {
public static void main(String[] args) {
try {
MyRemote remote = (MyRemote)Naming.lookup("rmi://127.0.0.1/myRemoteServer");
System.out.println(remote.sayHello());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}

}
}


启动:
1. 启动remiregistry服务(位于Java\jdk1.6.0_18\bin,启动的目录必须为你workspace的bin目录)
rmiregistry -J-Djava.rmi.server.codebase=file:/D:/FXworkspace/rmi/bin/

2. 执行MyRemoteImpl
3. 执行Client

结果输出:
server say hello to client

工作方式:

[img]http://dl.iteye.com/upload/attachment/452616/43e6babc-27da-38ad-aaca-ca3e91048bf6.jpg[/img]
1)客户到RMI registry中寻找
2)RMI registry返回stub对象。
3)客户调用stub方法,就像stub是真正的服务对象一样。


注:rmic是JDK内的一个工具,用来为一个服务类产生stub和skeleton。rmic有一些选项可以调整,包括不要产生skeleton、查看源代码、甚至使用IIOP作为协议。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值