一: RMI-----当一个系统需要调用另一个系统的方法时,最原始的纯java解决方案是RMI,它的步骤是首先定义一个接口继承Remote接口并自定义要暴露的方法并throws RemoteException,然后定义一个实现该接口的实现类,该类需要继承java.rmi.server.UnicastRemoteObject,另外在server类中的main 函数中用Naming.bind方法绑定url和具体的实现类。这样启动server后,服务器端便准备好服务。
分布式对象技术主要是在分布式异构环境下建立应用系统框架和对象构件。在应用系统框架的支撑下,开发者可以将软件功能封装为更易管理和使用的对象,这些对象可以跨越不同的软、硬件平台进行互操作。目前,分布式互操作标准主要有Microsoft的COM/DCOM标准、Sun公司的 Java RMI标准和OMG组织的CORBA标准。
Java RMI简介
远程方法调用(RMI,Remote Method Invocation)是jdk1.1中引入的分布式对象软件包,它的出现大大简化了分布异构环境中Java应用之间的通信。
要使用RMI,必须构建四个主要的类:远程对象的本地接口、远程对象实现、RMI客户机和RMI服务器。RMI服务器生成远程对象实现的一个实例,并用一个专有的URL注册。RMI客户机在远程RMI服务器上查找服务对象,并将它转换成本地接口类型,然后像对待一个本地对象一样使用它。
下面是一个简单的RMI实例,RMI客户机通过RMI服务器提供的方法输出一个语句。例子虽然很简单,但掌握了Java RMI调用的基本原理和方法,在实现复杂应用时,我们需要做的也只是完善远程对象的实现类而已。
RMI实例分析
1.远程对象的本地接口声明(RMIOperate.java)
· 该类仅仅是一个接口声明,RMI客户机可以直接使用它,RMI服务器必须通过一个远程对象来实现它,并用某个专有的URL注册它的一个实例。
· 远程接口扩展 java.rmi.Remote
接口。
· 除了所有应用程序特定的例外之外,每个方法还必须在 throws 子句中声明 java.rmi.RemoteException
(或 RemoteException
的父类)。
Hello.java
|
/* * @author javamxj (CSDN Blog) 创建日期 2004-12-27 */ import java.rmi.*; // RMI本地接口必须从Remote接口派生 public interface Hello extends Remote { // 接口中的具体方法声明,注意必须声明抛出RemoteException String sayHello(String name) throws RemoteException; }
|
2.远程对象实现类
这个类应实现RMI客户机调用的远程服务对象的本地接口,它必须从UnicastRemoteObject继承,构造函数应抛出RemoteException异常。
HelloImpl.java
|
/*
* @author javamxj (CSDN Blog) 创建日期 2004-12-27
*/
import java.rmi.*;
import javax.rmi.PortableRemoteObject;
public class HelloImpl extends PortableRemoteObject implements Hello {
/* 构造函数 */
public HelloImpl() throws RemoteException {
super();
}
/* 实现本地接口中声明的'sayHello()'方法 */
public String sayHello(String message) throws RemoteException {
System.out.println("我在RMI的服务器端,客户端正在调用'sayHello'方法。 ");
System.out.println("Hello " + message);
return message;
}
}
|
3.RMI服务器类
该类创建远程对象实现类HelloImpl的一个实例,然后通过一个专有的URL来注册它。所谓注册就是通过Java.rmi.Naming.bind()方法或 Java.rmi.Naming.rebind()方法,将HelloImpl实例绑定到指定的URL上。
HelloServer.java
|
/*
* @author javamxj (CSDN Blog) 创建日期 2004-12-27
*/
import java.rmi.*;
public class HelloServer {
public static void main(String[] args) {
// 在服务器端设置安全机制
/*
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
*/
try {
System.out.println("开始 RMI Server ...");
/* 创建远程对象的实现实例 */
HelloImpl hImpl = new HelloImpl();
System.out.println("将实例注册到专有的URL ");
Naming.rebind("HelloService", hImpl);
System.out.println("等待RMI客户端调用...");
System.out.println("");
} catch (Exception e) {
System.out.println("错误: " + e);
}
}
}
|
请注意有关 rebind
方法调用的下列参数:
- 第一个参数是 URL 格式的
java.lang.String
,表示远程对象的位置和名字。
- 需要将
myhost
的值更改为服务器名或 IP 地址。否则,如果在 URL 中省略,则主机缺省值为当前主机,而且在 URL 中无需指定协议(例如“HelloServer
”)。
- 在 URL 中,可以选择提供端口号:例如“/
/myhost:1234/HelloServer”。
端口缺省值为 1099。除非服务器在缺省 1099 端口上创建注册服务程序,否则需要指定端口号。
- 第二个参数为从中调用远程方法的对象实现引用。
- RMI 运行时将用对远程对象 stub 程序的引用代替由
hImpl
参数指定的实际远程对象引用。远程实现对象(如 HelloImpl
实例)将始终不离开创建它们的虚拟机。因此,当客户机在服务器的远程对象注册服务程序中执行查找时,将返回包含该实现的 stub 程序的对象。
4.RMI客户机类
· RMI客户使用java.rmi.Naming.lookup()方法,在指定的远程主机上查找RMI服务对象,若找到就把它转换成本地接口RMIOperate类型。它与CORBA不同之处在于RMI客户机必须知道提供RMI服务主机的URL,这个URL可以通过rmi://host/path或rmi: //host:port/path来指定,如果省略端口号,就默认使用1099。
· Java.rmi.Naming.lookup()方法可能产生三个异常:Java.rmi.RemoteException、Java.rmi.NotBoundException、 java.net. MalformedURLException,三个异常都需要捕获。
HelloClient.java
|
/*
* @author javamxj (CSDN Blog) 创建日期 2004-12-27
*/
import java.rmi.*;
public class HelloClient {
public static void main(String[] args) {
// 在服务器端设置安全机制
/*
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
*/
/* 默认为本地主机和默认端口 */
String host = "localhost:1099";
/* 带输入参数时,将host设置为指定主机 */
if (args.length > 0)
host = args[0];
try {
/* 根据指定的URL定位远程实现对象 */
/* “h”是一个标识符,我们将用它指向实现“Hello”接口的远程对象 */
Hello h = (Hello) Naming.lookup("rmi://" + host + "/HelloService");
System.out.println("实现“Hello”接口的远程对象: " + h);
System.out.println("我在客户端,开始调用RMI服务器端的'sayHello'方法");
System.out.println("欢迎, " + h.sayHello("javamxj blog"));
} catch (Exception ex) {
System.out.println("错误 " + ex);
}
}
}
|
5. 编译代码与运行系统:
在MS-DOS环境下,创建一个D:\RMISample目录,把上面4个文件复制到这个目录下,然后在此目录下新建两个文件夹:client和server(把它们分别看作是客户端与服务端)。
(1).编译所有的源代码
D:\RMISample> javac *.java
(2).生成客户端存根和服务器框架
D:\RMISample> rmic HelloImpl
这将生成HelloImpl_Stub.class和HelloImpl_Skel.class。
( 注:如果需要查看这两个类的源代码,可以使用“ rmic -keep HelloImpl”语句)
(3).把Hello.class、HelloClient.class、HelloImpl_Stub.class复制到client目录;
把Hello.class、HelloServer.class、HelloImpl_Skel.class、HelloImpl_Stub.class 复制到server目录。
(4).启动RMI注册
D:\RMISample\server>rmiregistry
(注:我是在命令控制台下运行这个系统的,必须开启三个控制台窗口,一个运行RMIRegistry,一个运行服务器,还有一个运行客户端。)
(5).运行和调用
● 在服务器上执行HelloServer
D:\RMISample\server>java HelloServer
● 在本地客户机上运行HelloClient
D:\RMISample\client>java HelloClient
● 在远程客户机上运行HelloClient(须指明RMI服务器主机名或IP地址)
java HelloClient 222.222.34.34
运行rmiregistry和server后的结果:
再运行Client后的结果:
还有一点要注意,在上面的例子中我注释了安全管理的代码,如果把注释去掉,那么需要建立一个安全策略文件,比如其文件名为 policy.txt,内容如下:
grant {
permission java.security.AllPermission "", "";
};
这是一条简单的安全策略,它允许任何人做任何事,对于你的更加关键性的应用,你必须指定更加详细安全策略。把这个文件复制到Client和Server目录,然后如下运行:
D:\RMISample\server>java -Djava.security.policy=policy.txt HelloServer
D:\RMISample\client>java -Djava.security.policy=policy.txt HelloClient
------------------------------------------Spring 提供的support-------------------------
1. 使用RmiServiceExporter提供服务
http://book.csdn.net/bookfiles/126/1001264299.shtml
Spring将RMI包装得更简单。使用Spring的RMI支持,应用可以透明地通过RMI提供服务。根本无须传统的RMI繁琐步骤:无须编写远程接口,无须编写远程服务主类。
在配置Spring的RMI,类似于远程EJB的配置,只是没有安全上下文传递和远程事务传递的支持。当使用RMI调用器时,可以插入应用的安全框架或安全逻辑。看下面的“远程”接口,注意对比前面传统RMI的远程接口。
public interface Person
{
//希望通过远程服务暴露的远程方法
public void useAxe();
}
该接口无须继承java.rmi.Remote接口,完全是一个普通接口。同样,该接口的实现类也是普通的JavaBean,该接口的实现类的源代码如下:
//实现Person接口
public class Chinese implements Person
{
//成员变量
private Axe axe;
public Chinese()
{
System.out.println("Spring实例化主调bean:Chinese实例...");
}
//依赖注入必须的setter方法
public void setAxe(Axe axe)
{
System.out.println("Spring执行依赖关系注入...");
this.axe = axe;
}
//实现Person接口必须实现的方法
public void useAxe()
{
System.out.println(axe.chop());
}
}
程序中的Chinese类不再需要继承java.rmi.server.UnicastRemoteObject类,只是个JavaBean。该类还依赖于Axe实例。这个实例不会作为远程服务暴露,仅仅作为Chinese的依赖使用。下面是Axe实例的接口和实现类:
Axe接口
public interface Axe
{
//该实例的业务方法
public String chop();
}
//Axe的实现类
public class SteelAxe implements Axe
{
public SteelAxe()
{
}
//实现Axe接口必须实现的方法
public String chop()
{
return "钢斧砍柴真快";
}
}
到目前为止,看到是两个简单的接口和对应的实现类。看不出任何提供远程服务的能力。Spring可以将Person接口里的方法作为远程服务暴露出来。 Spring暴露远程方法的类是RmiServiceExporter,该类可以将一个普通bean实例绑定成远程服务。将该bean实例绑定为远程服务的完整配置文件如下:
<?xml version="1.0" encoding="gb2312"?>
<!-- 指定Spring 配置文件的dtd>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<!-- Spring配置文件的根元素 -->
<beans>
<!-- 配置chinese的依赖bean-->
<bean id="steelAxe" class="lee.SteelAxe"/>
<!-- 配置chinese bean-->
<bean id="chinese" class="lee.Chinese" dependency-check="all">
<!-- 配置依赖注入-->
<property name="axe">
<ref local="steelAxe"/>
</property>
</bean>
<!-- 使用RmiServiceExporter 将目标bean暴露成远程服务-->
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- 指定暴露出来的远程服务名 -->
<property name="serviceName">
<!-- 远程服务名为chineseRemote-->
<value>chineseRemote</value>
</property>
<!-- 配置需要暴露的目标bean-->
<property name="service">
<ref bean="chinese"/>
</property>
<!-- 配置需要暴露的目标bean所实现的接口
该接口被远程接口对待-->
<property name="serviceInterface">
<value>lee.Person</value>
</property>
<!--1099是RMI的默认端口,指定RMI远程服务的端口 -->
<property name="registryPort"><value>1099</value></property>
</bean>
</beans>
从上面的配置文件看出,chinese bean没有丝毫独特之处。这正是Spring RMI支持的魅力:使用RmiServiceExporter,可以将普通bean实例作为RMI远程服务导出。该远程服务可以使用RmiProxyFactoryBean访问,也可以使用传统RMI业务访问该服务。
通常推荐使用RmiProxyFactoryBean来访问该服务,RmiProxyFactoryBean是个FactoryBean,与前面的FactoryBean相似,客户端请求时不会获得它本身,而是它产生的实例。
该远程服务随ApplicationContext初始化时启动,Spring会启动新线程来提供RMI服务,因此,提供RMI服务不会阻塞代码的执行。主程序如下:
public class BeanTest
{
public static void main(String[] args)throws Exception
{
//创建ApplicationContext实例
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
System.out.println("============");
}
}
主程序运行后,并不会立即结束——因为已经作服务器启动。第二行代码也会执行,并不会因为提供远程服务而阻塞。
2. 在客户端连接服务
客户端访问RMI远程服务访问步骤都是一样的。先通过JNDI查找,然后调用远程方法。看采用传统的客户端访问RMI远程服务,客户端如下:
public class RMIClient
{
public static void main(String[] args)throws Exception
{
//将查找的远程服务直接打印
System.out.println(Naming.lookup("rmi://localhost:1099/chineseRemote"));
//调用远程方法
//p.useAxe();
}
}
客户端可以通过JNDI查找到远程服务,但无法调用。将远程服务打印出来发现:
[java] RmiInvocationWrapper_Stub[UnicastRef [liveRef: [endpoint:[192.168.1.
100:1713](remote),objID:[-1282787d:10b8fe03f0d:-8000, 0]]]]
因为,并不是通过传统的RMI开发步骤提供的远程服务,客户端并没有提供stub类。因此,客户端不能通过常规方法调用远程服务。
Spring提供了RMI的客户端支持,Spring通过RmiProxyFactoryBean连接RMI远程服务。RmiProxyFactoryBean是个FactoryBean。Spring透明地创建调用器,使用RmiProxyFactoryBean使用该远程方法。客户端的配置文件如下:
<?xml version="1.0" encoding="gb2312"?>
<!-- 指定Spring 配置文件的dtd>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<!-- Spring配置文件的根元素 -->
<beans>
<!-- 配置Test bean-->
<bean id="test" class="lee.Test">
<!-- test bean依赖于远程服务-->
<property name="person">
<!-- 定义依赖bean,依赖bean通过远程服务获得-->
<ref bean="person"/>
</property>
</bean>
<!-- 通过RmiProxyFactoryBean 访问远程服务-->
<bean id="person" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<!-- 指定远程服务的url,后的服务名应与服务器端的服务名相同-->
<property name="serviceUrl">
<value>rmi://127.0.0.1:1099/chineseRemote</value>
</property>
<!-- 指定远程服务的接口名-->
<property name="serviceInterface">
<value>lee.Person</value>
</property>
</bean>
</beans>
客户端需要Person接口,这与传统的RMI方法并没有区别。客户端的主程序如下:
public class BeanTest
{
public static void main(String[] args)throws Exception
{
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
Test t = (Test)ctx.getBean("test");
t.test();
}
}
通过该主程序可以调用远程服务器端方法。而客户端本地没有Person实现类,只有一个Person接口,客户端程序并不关心Person的实现,即使不在本地都没有关系。
相关推荐
spring rmi 2.5.x版本与3.0.x版本不兼容解决方案
Spring通过提供RMI集成,简化了RMI服务的创建和调用。以下是一些关键点: 1. **服务接口定义**:首先,你需要定义一个远程服务接口,这个接口将包含你希望在远程进程中执行的方法。 2. **服务实现**:接着,创建该...
1.2 Spring的RMI支持:Spring通过`org.springframework.remoting.rmi.RmiServiceExporter`和`RmiProxyFactoryBean`简化了RMI的使用。`RmiServiceExporter`用于发布服务,而`RmiProxyFactoryBean`则用于创建RMI服务的...
10. **spring-support.jar** 提供了一些额外的功能支持,如缓存管理、定时任务、邮件服务等。 11. **spring-web.jar** 提供了Web应用程序支持,包括对Web环境下的上下文的支持,如Servlet容器初始化参数、会话...
3. 集成文档:可能包含了如何将RMI与Spring框架整合的教程,指导开发者如何在Spring环境中使用RMI-IIOP实现服务的发布和消费。 4. 相关资料:可能包含了关于RMI、IIOP和CORBA的基础知识,以及相关的技术文章和研究,...
5. **ASR**:Spring的Aspect Oriented Remoting(AOP远程)支持RMI、HTTP invokers和其他远程调用协议。 6. **测试**:Spring提供了测试支持,包括Mock对象、JUnit集成以及针对Web应用的测试支持。 7. **MVC的REST...
Spring Framework 是一种轻量级的解决方案,是构建你...明式事务管理,通过RMI或Web服务远程访问你的逻辑,以及用于持久存储数据的各种选项。 它提供了一个全功能的 MVC 框架,并使你能够将 AOP 透明地集成到你的软件中
而Spring Integration则更加灵活,它不仅可以独立运行,还可以与其他标准技术(如EJB、RMI、JMS等)协同工作,极大地简化了这些技术的使用。 ### 核心组件解析 #### 四、Spring Integration核心组件 - **Channels...
Spring框架提供了对RMI的支持,使得在Spring应用中集成RMI变得更加方便。标题"spring-rmi"暗示我们将探讨Spring框架与RMI的整合。 Spring RMI的核心概念包括服务接口、远程实现和服务注册。首先,我们需要定义一个...
9. **spring-security-remoting**:支持远程调用的安全控制,例如RMI和Hessian。 10. **spring-security-oauth**:虽然不在3.1.2版本内,但Spring Security通常与OAuth集成,提供开放授权功能,允许第三方应用安全...
【rmi-lite 1.0】是一个轻量级的Java Remote Method Invocation (RMI)实现,它是Java RMI技术的一个简化版本,适用于那些不需要完整RMI功能但仍然希望利用远程对象交互的项目。RMI是Java平台上的一个核心特性,它...
**Spring RMI 深度解析** Spring框架作为Java企业级应用开发的首选,提供了丰富的功能,包括对远程方法调用(Remote Method Invocation,RMI)的支持。RMI是Java平台上的一个核心特性,允许在分布式环境中进行对象...
在IT行业中,远程方法调用(Remote Method Invocation,RMI)和Spring框架是两个非常重要的概念,它们在分布式系统开发中发挥着关键作用。RMI是Java平台提供的一种技术,用于在不同Java虚拟机(JVM)之间进行对象间...
Spring RMI(Remote Method Invocation)是Java平台上的远程方法调用技术,结合Spring框架,能够帮助开发者轻松地创建分布式应用程序。在这个"Spring RMI小例子"中,我们将深入理解Spring如何简化RMI的使用,以及...
- **分布式系统**:支持远程服务调用,如RMI、JMS和Web服务。 - **AOP**:用于实现日志记录、安全控制、事务管理等横切关注点。 ### 依赖管理与命名规范 Spring框架提供了对多种依赖管理工具的支持,包括Maven和...
10. **spring-security-remoting-3.1.4.RELEASE.jar**:处理远程方法调用的安全性,如RMI、Hessian和 Burlap等远程调用协议的安全控制。 这些jar包共同构成了Spring Security 3.1.4的完整框架,为企业级应用提供了...
spring-rmi-示例 项目是从 code.google.com/p/springrmiexample 导出的,我这边稍作修改 这个项目是如何在 Spring 的帮助下设置 RMI 服务器和客户端的示例。 该项目包含2个子项目: Spring RMI 示例服务器,即 Web...
在"Lab1-RMI-code_layersmab_rmi_"这个实验中,我们将深入探讨RMI的基本概念、工作原理以及如何创建一个简单的RMI客户端和服务器。 1. **RMI基本概念**:RMI允许一个Java对象在一台机器上执行另一个Java对象的方法...
Spring Remote Method Invocation(RMI)是Java平台上的一个远程对象调用框架,它允许一个Java对象在一台机器上执行,并且被另一台机器上的客户端调用。在这个"SpringRMI小例子"中,我们将深入探讨如何利用Spring...
It covers the Spring Integration framework, including the declarative programming model, core messaging, adapters, and support for JMS, RMI, and web services. It's an ideal companion to Just Spring, ...