时髦的18章:Distributed Computing: RMI with a dash of servlets, EJB, and Jini

这是深入浅出 Java 程式设计 第二版18章 分散式运算 远端部署的RMI,这本书已经到了尾声了,最后这两章真是精彩,ㄚ琪觉得非常地受用,所以继续破例分享这一章。

建构远端服务

Step 1:建构Remote interface
远端的interface定义了用户端可以远端呼叫的method。它是个作为服务的多型化class。stub与服务都会实做此interface!

Step 2:实做Remote
这是真正执行的class。它实做出定义在该interface上的method。它是用户端会呼叫的物件。

Step 3:以rmic产生stub与skeleton
用户端与伺服器都有helper。你无须建构这些class或产生这些class的原始码。这都会在你执行JDK所附的rmic工具时自动的处理掉。
Step 4:启动RMI registry(rmiregistry)
rmiregistry就像是电话簿。使用者会从此处取得proxy(用户端的stub/helper)。

Step 5:启动远端服务
你必须服务物件开始执行。实做服务的class会起始服务的实体并向RMI registry登记。要有登记才能对用户提供服务。

这些真是金字良句啊,应该很多都不懂吧。继续看下去…

Step 1:建构Remote interface

①Extend过java.rmi.Remote
Remote是个标记性的interface,意味着没有method。然而它对RMI有特殊的意义,所以你必须遵守这项规则。注意的这里用的是extend,interface是可以extend过其他的interface。
public interface MyRemote extends Remote {

②宣告所有的method都会抛出RemoteException
import java.rmi.*;//Remote 在java.rmi中
public interface MyRemote extends Remote {
public String sayHello() throws RemoteException
}

③确定参数与回传值都是primitive或Serializable
如果使用的是API中像是String、primitive等主要的型别(包括阵列与集合),就没问题。如果是自订的型别,那你就得要实做Serializable。
public String sayHello() throws RemoteException;

Step 2:实做Remote

①实做Remote这个interface
你的服务必需要实做Remote – 就是用户端会呼叫的method。
public class MyRemoteImpl extends UniCastRemoteObject implements MyRemote {
public String sayHello() {
return “Server says, ‘Hey'”;
}
}

②extend过UnicastRemoteObject
public class MyRemoteImpl extends UniCastRemoteObject implements MyRemote {

③撰写宣告RemoteException的无参数constructor
public MyRemoteImpl throws RemoteException {}

④向RMI registry登记服务
有了远端服务,还必需要让远端用户存取。这可以透过将它初始化并加进RMI registry。当你登记物件时,RMI系统会把stub加到registry中,因为这是用户端所需要的。使用java.rmi.Naming的rebind()来登记服务。
try {
MyRemote service = new MyRemoteImpl();
Naming.rebind(“Remote Hello”,service);
} catch(Exception ex) {…}

Step 3:产生stub与skeleton

①对实做出的class(非interface)执行rmic
伴随Java Software Development Kit而来的rmic工具会以服务的实做产生两个新的class:stub与skeleton。它会依照命名规则在你的远端实做名称后面加上_Stub或_Skeleton。rmic有几个选项,包括了不产生skeleton、观察产出class的原始码、或使用IIOP作为通讯协定等。在此使用一般的方式。产出的class会放在目前目录下。要记住rmic必须能够找到你所实做的class,因此你或许要从实做所在的目录来执行rmic。

Step 4:启动RMI registry

①叫出命令来启动rmiregistry
要确定你是从可以存取到该class的目录来启动。最简单的方法就是从classes这个目录来跑。

Step 5:启动远端服务

①叫出另一个命令列来启动服务
这可能是从你所实做的class上的main()或独立的启动用class来进行。在这个简单的范例中,把启动程式码放在class的实作中,它的main()会将物件初始化并把它登记给RMI registry。

用户端如何取得stub物件?

①用户端查询RMI registry
Naming.lookup(“rmi://127.0.0.1/Remote Hello”);

②RMI registry传回stub物件
且RMI会自动的将stub解序列化。你必须要有rmic所产生的stub class,否则用户端的stub不会被解序列化。

③用户端就像取用真正的服务一样的叫用stub上的method

确定每台机器都有所须的class档案

使用RMI时程式设计师最常犯的三个错:

1)忘记在启动远端服务前启动rmiregistry(使用Naming.rebind()登记服务前rmiregistry必须启动!)

2)忘记把参数与回传型别做成可序列化(编译器不会侦测到,执行时才会发现)

3)忘记将stub的class交给用户端

ㄚ琪在实做时,在执行rmiregistry时发生:

Warning: JIT compiler “symcjit” not found. Will use interpreter.
security properties not found. using defaults.

这样的错误,后来查到要把C:\Program Files\Java\jdk1.6.0_29\bin加到PATH变数最前面,这是因为还有其它的Java执行环境所干扰,这样做可以避免错误

在执行MyRemoteImpl这支程式时,会发生这样的错误:

java.net.MalformedURLException: invalid URL String: Remote Hello
at java.rmi.Naming.parseURL(Naming.java:226)
at java.rmi.Naming.rebind(Naming.java:154)
at MyRemoteImpl.main(MyRemoteImpl.java:12)
Caused by: java.net.URISyntaxException: Illegal character in path at index 6: Re
mote Hello
at java.net.URI$Parser.fail(URI.java:2809)
at java.net.URI$Parser.checkChars(URI.java:2982)
at java.net.URI$Parser.parseHierarchical(URI.java:3066)
at java.net.URI$Parser.parse(URI.java:3024)
at java.net.URI.<init>(URI.java:578)
at java.rmi.Naming.intParseURL(Naming.java:256)
at java.rmi.Naming.parseURL(Naming.java:220)
… 2 more

一开始还真看不懂这是什么错误?一直在猜,后来读到Illegal character in path at index 6: Remote Hello
嗯,第6个字是空格,空格不符合语法,ㄚ琪就在猜不要用空格看看,在MyRemoteImpl.java里的Remote Hello改成Remote_Hello,Yes,行!另外在MyRemoteClient.java里

MyRemote service = (MyRemote) Naming.lookup(“rmi://127.0.0.1/Remote Hello”);

也改成

MyRemote service = (MyRemote) Naming.lookup(“rmi://127.0.0.1/Remote_Hello”);

没错,这样子就对了,看来不允许空格的字元,这是目前使用jdk1.6.0_29会有这样的问题,请各位注意。

建构与执行servlet的步骤

Step 1:找出可以放servlet的地方

Step 2:取得servlets.jar并加到classpath上

Step 3:经由extend过HttpServlet来撰写servlet的class
public class MyServletA extends HttpServlet {…}

Step 4:撰写HTML来叫用servlet

Step 5:设定HTML网页与servlet给伺服器

呼,过去的就让它过去吧,终于读完了,后面虽然还有很多附录、很多程式码,但是我想ㄚ琪自己都可以解决,很高兴又看完了一本巨作,这一本很赞,值得一读。