RMI应用程序通常包括两个独立的程序:服务器程序和客户机程序。典型的服务器应用程序将创建多个远程对象,使这些远程对象能够被引用,然后等待客户机调用这些远程对象的方法。而典型的客户机程序则从服务器中得到一个或多个远程对象的引用,然后调用远程对象的方法。RMI为服务器和客户机进行通信和信息传递提供了一种机制。
在与远程对象的通信过程中,RMI使用标准机制:stub和skeleton。远程对象的stub担当远程对象的客户本地代表或代理人角色。调用程序将调用本地stub的方法,而本地stub将负责执行对远程对象的方法调用。在RMI中,远程对象的stub与该远程对象所实现的远程接口集相同。调用stub的方法时将执行下列操作:
(1) 初始化与包含远程对象的远程虚拟机的连接;
(2) 对远程虚拟机的参数进行编组(写入并传输);
(3) 等待方法调用结果;
(4) 解编(读取)返回值或返回的异常;
(5) 将值返回给调用程序。为了向调用程序展示比较简单的调用机制,stub将参数的序列化和网络级通信等细节隐藏了起来。在远程虚拟机中,每个远程对象都可以有相应的skeleton(在JDK1.2环境中无需使用skeleton)。Skeleton负责将调用分配给实际的远程对象实现。它在接收方法调用时执行下列操作:(1) 解编(读取)远程方法的参数;(2) 调用实际远程对象实现上的方法;(3) 将结果(返回值或异常)编组(写入并传输)给调用程序。stub和skeleton由rmic编译器生成。
利用RMI编写分布式对象应用程序需要完成以下工作:(1) 定位远程对象。应用程序可使用两种机制中的一种得到对远程对象的引用。它既可用RMI的简单命名工具rmiregistry来注册它的远程对象,也可以将远程对象引用作为常规操作的一部分来进行传递和返回。(2)与远程对象通信。远程对象间通信的细节由RMI处理,对于程序员来说,远程通信看起来就像标准的Java方法调用。(3)给作为参数或返回值传递的对象加载类字节码。因为RMI允许调用程序将纯Java对象传给远程对象,所以,RMI将提供必要的机制,既可以加载对象的代码又可以传输对象的数据。在RMI分布式应用程序运行时,服务器调用注册服务程序以使名字与远程对象相关联。客户机在服务器上的注册服务程序中用远程对象的名字查找该远程对象,然后调用它的方法。
以上是百度对RMI的描述. 接下来是我的例子:
---------------------------------------------------------
//用于在客户端与服务端间传送的参数对象,必须实现Serializable 接口
package server.entity;
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = -7937279105651707960L;
private String name;
private int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
String result = "my name is: "+this.name+" my age is: "+this.age;
return result;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//远程对象接口
package server.service;
import java.rmi.Remote;
import server.entity.Student;
public interface IRemoteService extends Remote {
public Student fullfillStudent(Student student)throws java.rmi.RemoteException;
public Student createStudent(String name,int age) throws java.rmi.RemoteException;
public String sayHello(String name) throws java.rmi.RemoteException;
}
//远程对象
package server.service.impl;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import server.entity.Student;
import server.service.IRemoteService;
public class RemoteServiceImpl extends UnicastRemoteObject implements IRemoteService {
public RemoteServiceImpl() throws RemoteException {
super();
}
private static final long serialVersionUID = -5321327076322429303L;
@Override
public Student createStudent(String name,int age) {
return new Student(name,age);
}
@Override
public String sayHello(String name) {
return "hi~, "+name;
}
@Override
public Student fullfillStudent(Student student) {
student.setName("default");
student.setAge(111);
return student;
}
}
//服务端的Server,注册一个远程对象并进行绑定,之后就等客户端发送请求
package server;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import server.service.IRemoteService;
import server.service.impl.RemoteServiceImpl;
public class Server {
public static void main(String[] args) {
try {
//System.setSecurityManager(new RMISecurityManager());
IRemoteService impl = new RemoteServiceImpl();
LocateRegistry.createRegistry(2099);
Naming.rebind("rmi://127.0.0.1:2099/yyb", impl);
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
//客户端,向服务端发送请求
package client;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import server.entity.Student;
import server.service.IRemoteService;
public class Client {
public static void main(String[] args) {
try {
IRemoteService server = (IRemoteService) Naming.lookup("rmi://127.0.0.1:2099/yyb");
Student stu1 = server.fullfillStudent(new Student());
Student stu2 = server.createStudent("b",2);
System.out.println("fullfillStudent----"+stu1);
System.out.println("createStudent----"+stu2);
System.out.println(server.sayHello("everybody"));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}
至此,rmi所需的类已备齐,然后就是编译了。编译后,还要在命令行中定位到编译后的类根目录,然后rmic server.service.impl.RemoteServiceImpl 生成Stub。
以上是通过原生java来实现rmi,下面是通过spring来实现的。
-----------------------------------------------------------------------------
//远程对象,这里一定要注意,它不能extends UnicastRemoteObject, 因为UnicastRemoteObject的默认构造函数调用了UnicastRemoteObject.exportObject(Remote obj, int port)。而RmiServiceExporter的prepare方法也调用了UnicastRemoteObject.exportObject(Remote obj, int port),所以会抛异常的。
package server.service.impl;
import server.entity.Student;
import server.service.IRemoteService;
public class RemoteServiceImpl_spring implements IRemoteService {
@Override
public Student createStudent(String name,int age) {
return new Student(name,age);
}
@Override
public String sayHello(String name) {
return "hi~, "+name;
}
@Override
public Student fullfillStudent(Student student) {
student.setName("default");
student.setAge(111);
return student;
}
}
//服务端的applicationContext_server.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="remoteService" class="server.service.impl.RemoteServiceImpl_spring"></bean>
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="yyb"/>
<property name="service" ref="remoteService"/>
<property name="serviceInterface" value="server.service.IRemoteService"/>
<!--
<property name="registryHost" value="127.0.0.1"/>
-->
<property name="registryPort" value="2099"/>
</bean>
</beans>
//服务端的Server,读取applicationContext_server.xml,之后就等客户端发送请求
package server;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Server_spring {
public static void main(String[] args) {
new FileSystemXmlApplicationContext("src/server/applicationContext_server.xml");
}
}
//客户端的applicationContext_client.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="rmiService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://127.0.0.1:2099/yyb"></property>
<property name="serviceInterface" value="server.service.IRemoteService"></property>
</bean>
</beans>
//客户端,向服务端发送请求
package client;
import java.rmi.RemoteException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import server.entity.Student;
import server.service.IRemoteService;
public class Client_spring {
public static void main(String[] args) {
ApplicationContext ac = new FileSystemXmlApplicationContext("src/client/applicationContext_client.xml");
IRemoteService server = (IRemoteService) ac.getBean("rmiService");
try {
Student stu1 = server.fullfillStudent(new Student());
Student stu2 = server.createStudent("b",2);
System.out.println("fullfillStudent----"+stu1);
System.out.println("createStudent----"+stu2);
System.out.println(server.sayHello("everybody"));
} catch (RemoteException e) {
e.printStackTrace();
}
}
}