1. 程式人生 > >JAVA RMI技術及其spring封裝的使用

JAVA RMI技術及其spring封裝的使用

                     

java RMI即java遠端服務呼叫,用於各個子系統之間的服務呼叫。最近應用到了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;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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();    }    @Override    public String sayHello(String name) throws RemoteException {        return "Welcome, " + name;    }    @Override    public int sum(int a, int b) throws RemoteException{        return a + b;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

說明:介面的實現類同時要實現 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();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

說明:繫結的地址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();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

執行,顯示,成功。 呵呵,是不是很簡單?對吧。 下面我們要使用spring封裝的Java RMI技術,也是很多專案都會用到的。下面我有個Spring RMI的例子。

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);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、介面的實現類

package leon.rmi.impl;import leon.rmi.iface.IUserDao;public class UserDaoImpl implements IUserDao {    @Override    public String getUserList() {        return "Hello,Get the user list from database!";    }    @Override    public int sum(int a, int b) {        return a+b;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/security    http://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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

說明:這裡不詳細的說明了,主要配置了真實實現類,用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/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/security    http://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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

這裡注意到RmiProxyFactoryBean的兩個重要的引數: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));    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

執行,成功。 好了,這就是一個採用Spring封裝的RMI的例子,專案工作中應該經常使用的。

上面的spring配置都使用了<beans:bean><beans:property ... /></beans:bean>這樣的標籤配置bean和引數, 是因為xmlns="http://www.springframework.org/schema/security"這個配置指明瞭這個檔案的預設schema為security, 所以裡面的beans定義就需要加上字首beans,現在基本都這麼配:xmlns="http://www.springframework.org/schema/beans", 這樣以來直接使用<bean><property ... /></bean>就可以了,更加方便。