一、Java RMI簡介
Java RMI(Remote Method Invocation,遠端方法調用),允許運作在一個Java虛拟機的對象調用運作在另一個Java虛拟機上的對象的方法。在RMI中的核心是遠端對象(remote object),除了對象本身所在的虛拟機,其他虛拟機也可以調用此對象的方法,而且這些虛拟機可以是運作在網絡上的不同計算機中。
1、1 RMI原理
RMI是基于遠端消息交換協定JRMP( Java Remote Method Protocol)協定通信,這個協定類似于HTTP協定,規定了用戶端和服務端通信要滿足的規範。JRMP是專為Java的遠端對象制定的協定,由于JRMP是專為Java對象制定的,是以,RMI對于用非Java語言開發的應用系統的支援不足。不能與用非Java語言書寫的對象進行通信(意思是隻支援用戶端和伺服器端都是Java程式的代碼的遠端調用)。Java RMI通信模型如下圖所示:

RMI遠端調用步驟:
1,客戶調用用戶端本地對象stub上的方法
2,用戶端對象stub封裝好調用資訊,然後通過網絡發送給服務端對象skeleton
3,服務端對象skeleton将用戶端對象發送來的調用資訊解析,然後找對正在調用的對象及方法。
4,執行對應方法,然後将結果傳回給服務端對象skeleton
5,服務端對象将結果傳回給用戶端對象Stub。
6,用戶端對象将傳回結果傳回給調用者
二、Java RMI代碼實作
2、1簡單Java代碼實作
服務端:
1、建立實體類
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
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;
}
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
這個類需要實作Serializable接口,用于資訊的傳輸。
2、服務端遠端接口定義
public interface RmiService extends Remote{
public String getUserInfo ()throws RemoteException;
public String getName() throws RemoteException;
}
接口必須繼承Remote類,每一個定義地方法都要抛出RemoteException異常對象。
3、接口具體實作類定義
public class RmiServiceImpl extends UnicastRemoteObject implements RmiService{
/**
*
*/
private static final long serialVersionUID = 1L;
public RmiServiceImpl() throws RemoteException {
super();
}
@Override
public String getUserInfo() throws RemoteException {
// TODO Auto-generated method stub
User user = new User();
user.setName("張三");
user.setAge(18);
return user.toString();
}
@Override
public String getName() throws RemoteException {
// TODO Auto-generated method stub
return "李四";
}
}
這個類需要實作上面的接口,還需要繼承UnicastRemoteObject類和顯示寫出無參的構造函數。
4、建立啟動類啟動服務
public static void main(String[] args) throws RemoteException,NamingException{
// TODO Auto-generated method stub
RmiService service = new RmiServiceImpl();
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("service", service);
//或者使用下列的
/*try {
Naming.rebind("rmi://127.0.0.1:1099/service", service);
//Naming.rebind("service", service);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
System.out.println(" rmi server is ready ...");
}
用戶端:
1、将服務端的實體類以及遠端接口(User和RmiService )打成jar包導入到用戶端程式中,然後建立用戶端程式進行調用。
public static void main(String[] args){
RmiService service;
try {
Registry registry = LocateRegistry.getRegistry("localhost",1099);
service = (RmiService)registry.lookup("service");
//service = (RmiService)Naming.lookup("service");
//service = (RmiService)Naming.lookup("rmi://127.0.0.1:1099/service");
System.out.println(service.getUserInfo());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
2.2、在spring中配置Java RMI
服務端:
1、定義實體類(和上面類似)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
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;
}
@Override
public String toString() {
return name+age+"歲!";
}
}
需要實作Serializable接口
2、定義遠端接口
public interface RMIService {
public String getUserInfo();
}
和上面不同的是這是一個普通的接口,不需要繼承其他接口
3、定義接口實作類
public class RMIServiceImpl implements RMIService{
private User user;
@Override
public String getUserInfo() {
// TODO Auto-generated method stub
return user.toString();
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
隻需實作遠端接口即可,不需要其他操作
4、配置spring
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="rMIServiceImpl" class="com.test.service.impl.RMIServiceImpl">
<property name="user" ref="user"/>
</bean>
<bean id="user" class="com.test.bean.User" >
<property name="name" value="張三"/>
<property name="age" value="19" />
</bean>
<!-- 定義服務端接口 -->
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- 将遠端接口實作類對象設定到RMI服務中 -->
<property name="service" ref="rMIServiceImpl" />
<!-- 設定RMI服務名,将作為RMI用戶端的調用接口-->
<property name="serviceName" value="rmiservice" />
<!-- 将遠端接口設定為RMI服務接口 -->
<property name="serviceInterface" value="com.test.service.RMIService" />
<!-- 為RMI服務端遠端對象系統資料庫設定端口号-->
<property name="registryPort" value="9090" />
</bean>
</beans>
5、建立啟動類啟動RMI服務
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
System.out.println("RMI啟動成功!");
}
啟動成功截圖
用戶端:
1、将服務端的實體類以及遠端接口(User和RmiService )打成jar包導入到用戶端程式中
2、配置服務端spring配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--bean id為程式調用時輸入的第一參數-->
<bean id="rmiservice" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<!--ip和端口為server的ip和剛才注冊的端口号,服務名為設定的serviceName-->
<property name="serviceUrl" value="rmi://localhost:9090/rmiservice"/>
<!--調用的接口-->
<property name="serviceInterface" value="com.test.service.RMIService"/>
<!-- 當連接配接失敗時是否重新整理遠端調用stub -->
<property name="refreshStubOnConnectFailure" value="true"/>
</bean>
</beans>
3、建立用戶端程式調用RMI服務
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
RMIService rmiservice = (RMIService)ctx.getBean("rmiservice");
System.out.println(rmiservice.getUserInfo());
}
傳回結果。