最近應用到了Java RMI技術,所以總結一下RMI的使用,另外EJB的實現也是以Java RMI為基礎核心的。RMI遠程方法調用,可以跨機器通過網路調用,不過Java RMI只支援兩邊都是Java程式,如果要實現完全兩邊異構,那麼就要用到傳說中的Web Service了。為了看好效果,都要建立兩個或兩個以上工程,當然,如果你有兩個機器並通過區域網路相連更好,如果能同有互連網的條件就更好了,以下是同一機器不同工程的實驗。
Java RMI
首先建立一個工程,隨便什麼工程,為了方便,就Java Project吧。
1、建立一個介面,繼承Remote
package leon.rmi.iface;import java.rmi.Remote;import java.rmi.RemoteException;/*** 定義遠程介面,必須繼承Remote介面,* 其中所有需要遠程調用的方法都必須拋出RemoteException異常 */ public interface IHello extends Remote { public String sayHello(String name) throws RemoteException; public int sum(int a, int b)throws RemoteException;}
2、建立介面的實作類別
package leon.rmi.impl;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;import leon.rmi.iface.IHello;public class HelloImpl extends UnicastRemoteObject implements IHello {private static final long serialVersionUID = 1L;public HelloImpl() throws RemoteException {super();}@Overridepublic String sayHello(String name) throws RemoteException {return "Welcome, " + name;}@Overridepublic int sum(int a, int b) throws RemoteException{return a + b;}}
說明:介面的實作類別同時要實現Serializable介面,這裡繼承UnicastRemoteObject也是間接實現Serializable介面,同時,因為構造方法需要拋出RemoteException,所以不能預設使用隱含的無參構造方法,而應該自己顯式定義構造方法。
3、建立應用類,註冊和啟動服務端RMI,以被用戶端調用
package leon.rmi.impl;import java.net.MalformedURLException;import java.rmi.AlreadyBoundException;import java.rmi.Naming;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import leon.rmi.iface.IHello;public class HelloServer {public static void main(String args[]) {try {//建立一個遠程對象IHello rhello = new HelloImpl();//產生遠程對象註冊表Registry的執行個體,並指定連接埠為8888(預設連接埠是1099)LocateRegistry.createRegistry(8888);//把遠程對象註冊到RMI註冊伺服器上,並命名為RHello//綁定的URL標準格式為:rmi://host:port/name(協議名可以省略,下面兩種寫法都可以)Naming.bind("rmi://10.225.112.86:8888/RHello", rhello);//Naming.bind("//10.225.112.86:8888/RHello",rhello);System.out.println(">>INFO:遠程IHello對象綁定成功!");} catch (RemoteException e) {System.out.println("建立遠程對象發生異常!");e.printStackTrace();} catch (AlreadyBoundException e) {System.out.println("發生重複綁定對象異常!");e.printStackTrace();} catch (MalformedURLException e) {System.out.println("發生URL畸形異常!");e.printStackTrace();}}}
說明:綁定的地址10.225.112.86是我的區域網路地址可以在DOS命令列用ipconfig查看,如果你的機器沒有任何連網,可以使用127.0.0.1或localhost。
運行HelloServer.java看到,紅色方塊顯示正在運行:
>>INFO:遠程IHello對象綁定成功!
好了,現在遠程服務提供端建立完成,下面建立用戶端。
建立一個新的工程,為了方便,也是Java Project吧,
1、 因為用戶端需要有服務端那邊提供的介面,才可以訪問,所以要將服務端的IHello介面完全拷貝(連同包)到用戶端,當然為了方便,你在用戶端工程中建立一個完全一樣的介面也可以。實際運用中通常是要服務端介面打成jar包來提供的。
2、 建立用戶端調用類
package testrmi;import java.rmi.Naming;import leon.rmi.iface.IHello;public class HelloClient {public static void main(String args[]) {try {// 在RMI服務註冊表中尋找名稱為RHello的對象,並調用其上的方法IHello rhello = (IHello) Naming.lookup("rmi://10.225.112.86:8888/RHello");System.out.println(rhello.sayHello("水哥"));System.out.println(rhello.sum(454, 5457));} catch (Exception e) {e.printStackTrace();}}}
運行,顯示,成功。
呵呵,是不是很簡單?對吧。
下面我們要使用Spring封裝的Java RMI技術,也是很多項目都會用到的。後面我有個Spring RMI的例子。要看懂下面Spring的例子,你需要已經會用Spring,會配置Spring,否則怕你看不懂,所以如果還不懂Spring的,先學學Spring,入下門吧。
Spring RMI
Spring RMI中,主要有兩個類:org.springframework.remoting.rmi.RmiServiceExporter和org.springframework.remoting.rmi.RmiProxyFactoryBean
服務端使用RmiServiceExporter暴露RMI遠程方法,用戶端用RmiProxyFactoryBean間接調用遠程方法。
首先,也是兩個工程,服務端用Web工程,因為使用Spring,我們依託Web容器來完成。
1、在該服務端Web工程中添加介面,普通介面,無需繼承其他
package leon.rmi.iface;public interface IUserDao {public String getUserList();public int sum(int a, int b);}
2、介面的實作類別
package leon.rmi.impl;import leon.rmi.iface.IUserDao;public class UserDaoImpl implements IUserDao {@Overridepublic String getUserList() {return "Hello,Get the user list from database!";}@Overridepublic int sum(int a, int b) {return a+b;}}
3、在該服務端Web工程中添加Spring的bean設定檔,比如命名為rmi.xml,內容如下:
<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/security"xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security-3.0.xsd"><beans:bean id="userDaoRmi" class="leon.rmi.impl.UserDaoImpl"> </beans:bean> <beans:bean id="userSvcExporter" class="org.springframework.remoting.rmi.RmiServiceExporter"> <beans:property name="service" ref="userDaoRmi"/> <beans:property name="serviceName" value="userDaoService"/> <beans:property name="serviceInterface" value="leon.rmi.iface.IUserDao"/> <beans:property name="registryPort" value="9111"/> <beans:property name="servicePort" value="10023"/> </beans:bean> </beans:beans>
說明:這裡不詳細的說明了,主要配置了真實實作類別,用RmiServiceExporter暴露時,配置property要注意的有service,serviceName,serviceInterface,連接埠registryPort。
啟動Web工程的伺服器,該設定檔應該被Spring的監聽器監聽,並載入,啟動成功後,服務端就算建好了。如果伺服器是在localhost啟動的,那麼暴露的RMI的IP也是localhost,如果需要使用其他IP,需要讓伺服器在其他的IP啟動。
好了,吃完午飯繼續寫
用戶端調用
為了方便也只建立一個簡單的Java Project,使用靜態java代碼來調用了。
1、 在源檔案src下建立一個springbeans.xml
<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/security"xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security-3.0.xsd"> <beans:bean id="userDaoProxy" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> <beans:property name="serviceUrl" value="rmi://localhost:9111/userDaoService"/> <beans:property name="serviceInterface" value="leon.rmi.iface.IUserDao"/> </beans:bean> </beans:beans>
這裡注意到RmiProxyFactoryBean的兩個重要的property:serviceUrl和serviceInterface,IUserDao介面可以從服務端的介面打成jar包來提供。
2、 建立java類
package testrmi;import leon.rmi.iface.IUserDao;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestRMI2 {public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("springbeans.xml"); IUserDao userDao = (IUserDao) ctx.getBean("userDaoProxy"); System.out.println(userDao.getUserList()); System.out.println(userDao.sum(145, 487));}}
運行,成功。
好了,這就是一個採用Spring封裝的RMI的例子,項目工作中應該經常使用的。
有什麼問題,歡迎討論交流。