RMI應用部署

cl723401發表於2018-11-06

最近在看《JAVA網路程式設計精解》到第十章突然迷糊了,怎麼都看不懂怎麼部署的,特別是在伺服器與客戶程式分佈不同機器上的時候,java.rmi.server.codebase的時候,總是出現ClassNotFoundException。下面說說RMI應用程式的部署過程。

RMI應用由3部分組成,伺服器、客戶端和登錄檔程式,這三個程式部署由三種方式部

1.伺服器、客戶端和登錄檔程式在同一臺的機器上,一般實驗的時候可以使用,教材上都採用這種模式。

2.伺服器與登錄檔程式執行在一臺機器,而客戶端執行在另一臺機器上。下面講的就是這種方式

3.伺服器、登錄檔、客戶端程式執行於三個不同的機器,這時就需要設定java.rmi.server.codebase=path,來讓登錄檔程式能夠通過path找到遠端物件的介面類,並完成註冊。實際上jdk5以後,採用動態代理生成stub類,客戶端和(伺服器-登錄檔分離時),通過java.rmi.server.codebase=path指名stub類的地址

關於java.rmi.server.codebase具體可以參考官方文件https://docs.oracle.com/javase/6/docs/technotes/guides/rmi/hello/hello-world.html

對於第二種部署方式,可以參考:https://segmentfault.com/a/1190000004494341#articleHeader22這裡詳細說明了兩臺機器上的不熟方式:關於上面連結程裡有些不清楚的,我給出我的理解:

首先客戶與伺服器分離,分別建立java專案作為伺服器和客戶端

RMIClient

Client

RMMIServer:Hello

package com.cl.remote;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello  extends Remote{

String sayHello() throws RemoteException;	
}

RMMIServer:Server 

 

package com.cl.remote;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class Server implements Hello{

	public Server() {
		super();
	}
	@Override
	public String sayHello() throws RemoteException {
		// TODO Auto-generated method stub
		return "Hello World";
	}
	
	public static void main(String[] args) {
		System.setProperty("java.security.policy",Server.class.getResource("rmi.policy").toString());
		if(System.getSecurityManager()==null){
			System.setSecurityManager(new SecurityManager());
		}
		
		try {
			Registry registry=LocateRegistry.createRegistry(1099);
			
			Server obj=new Server();
			Hello stub=(Hello) UnicastRemoteObject.exportObject(obj,1099);
			registry.bind("Hello", stub);
			System.out.println();
			 System.err.println("Server ready");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

 

RMIClient:Client

package com.cl.client;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import com.cl.remote.Hello;


public class Client {

	public static void main(String[] args) {
		//System.out.println(Client.class.getResource("rmi.policy").toString());
		//file:/E:/myprograms/WorkPlaceForEclipse_Java_NetProgram/RMIApp/bin/com/cl/rmi_test2/rmi.policy
		System.setProperty("java.security.policy",Client.class.getResource("rmi.policy").toString());
		if(System.getSecurityManager()==null){
			System.setSecurityManager(new SecurityManager());
		}
		String host = (args.length<1)?null:args[0];
		String port=(args.length<2)?"1099":args[1];
		try {
			Registry registry=LocateRegistry.getRegistry(host,Integer.parseInt(port));
			Hello stub=(Hello) registry.lookup("Hello");
			String response=stub.sayHello();
			System.out.println("response:" +response);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

RMIClient:Hello

package com.cl.remote;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello  extends Remote{

String sayHello() throws RemoteException;	
}

值得注意的是RMIClient和RMMIServer的Hello完全一樣(包名也一樣)具體客戶端的介面類參考https://blog.csdn.net/gaohuanjie/article/details/38338765

客戶端一定需要遠端的介面類檔案,因為需要在客戶端呼叫遠端類的遠端方法,如果沒有這個類編譯是過不去的。開始我以為《JAVA網路程式設計精解》裡提到的客戶端沒有服務端的類檔案,以為是客戶端可以沒有遠端介面類檔案,結果最後才發現作者提到的是

如果Hello包名在客戶端與服務端設定的不一樣,會導致客戶端Hello stub=(Hello) registry.lookup("Hello");轉型時出錯,因為返回的是com.cl.remote.Hello的存根類,而Client本地的Hello包名不是com.cl.remote話,是無法強轉的。

rmi.policy參考https://segmentfault.com/a/1190000004494341#articleHeader22

部署過程:

1.win10上執行伺服器程式:

因為在程式裡設定了java.security.policy,不用再使用java -Djava.security.policy設定,客戶端也一樣。

2.lunix下部署客戶端程式:

將RMIClient的bin目錄拷到lunix下,如圖:

隨後輸入:

其中192.168.56.1是win10主機的IP,1099是埠,可以發現lunix下輸出了:

於是部署執行完成。

歡迎大家與我討論RMI.

相關文章