这两天看《精通RMI--Java与EJB企业级应用开发》,打算学习一下rmi,好写个EJB网站作业,但是作者Rickard Oberg 讲解的都是重点部分,没什么实现细节,像我这样的入门这,光是对第一个基本实现HelloWorld就折腾了一天,不过总算是折腾明白了一点东西,在这里记下。
其实学习这个例子最大的担心,是害怕在Fedora中运行不好,虽然java是夸平台的,但是长久以来折腾linux,发现所有在windows下能正常实现的,在linux下都不一定能行,况且这本书的作者案例也是在windows下实现的,所以我就怕怕的。虽然事后证明我是杞人忧天,不过这个担忧的确让我在遇到阻碍是总有个心病。
首先我还是描述以下我在实现HelloWorld中的困难吧,其实很弱智,就是在运行rmiregistry命令是当前目录不再Project编译的bin目录下,结果出了错如下:
the object could not be created
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
...
所以说不懂常识真可怕!
解决了这个问题,其他的就一马平川了,因为大部分都是按照书上的来。下面是顺利的部分,先看一下我的包分布:
src
├── Build.sh
└── helloworld
├── client
│ └── Client.java
├── interfaces
│ └── HelloWorld.java
└── server
├── HelloWorldImpl.java
└── Server.java
在包helloworld.inerfaces下是HelloWorld的接口:
HelloWorld.java
--------------------------------------------------------------------------------
package helloworld.interfaces;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloWorld
extends Remote
{
public static String NAME = "HelloWorld";
public String helloWorld(String name)
throws RemoteException;
}
在包helloworld.server下是HelloWorldImpl远程对象和Server管理器:
HelloWorldImpl.java
--------------------------------------------------------------------------------------------
package helloworld.server;
import java.rmi.RemoteException;
import java.rmi.server.RemoteServer;
import java.rmi.server.UnicastRemoteObject;
import helloworld.interfaces.HelloWorld;
public class HelloWorldImpl
extends RemoteServer
implements HelloWorld
{
public HelloWorldImpl()
throws RemoteException
{
UnicastRemoteObject.exportObject(this);
}
public String helloWorld(String name)
throws RemoteException
{
return "Hello" + name + "!";
}
}
Server.java
--------------------------------------------------------------------------------------------------
package helloworld.server;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import helloworld.interfaces.HelloWorld;
import helloworld.server.HelloWorldImpl;
public class Server
{
public static void main(String[] args)
throws Exception
{
new Server();
}
public Server()
{
try{
HelloWorld server = new HelloWorldImpl();
Naming.rebind(HelloWorld.NAME, server);
System.out.println("Server is ready");
}catch(MalformedURLException e)
{
System.out.println("The server name was incorrect");
e.printStackTrace(System.err);
}catch (RemoteException e)
{
System.out.println("the object could not be created");
e.printStackTrace(System.err);
}
}
}
在helloworld.client包下是Client客户端程序:
Client.java
---------------------------------------------------------------------------------
package helloworld.client;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Properties;
import helloworld.interfaces.HelloWorld;
public class Client
implements Runnable
{
public static void main(String[] args)
throws Exception
{
new Client().run();
}
public void run()
{
try
{
HelloWorld server = (HelloWorld)Naming.lookup
(HelloWorld.NAME);
System.out.println(server.helloWorld("world"));
}catch (NotBoundException e)
{
System.out.println("The server could not be found");
e.printStackTrace(System.err);
}catch (MalformedURLException e)
{
System.out.println("The server name was incorrect");
e.printStackTrace(System.err);
}catch (Exception e)
{
System.out.println("The object could not be created");
e.printStackTrace(System.err);
}
}
}
--------------------------------------------------------------------------------------------------
以上是全部代码
--------------------------------------------------------------------------------------------------
接着执行的步骤是:
NO.1 javac 编译
NO.2 rmic生成stub
NO.3 在class目录下运行rmiregistry
No.4 java helloworld.server.Server
No.5 java helloworld.client.Client
还有其他一些安全策略和编译时用到的参数,我还有尚未明白的地方,不过网上讲解挺多。
不得不说,这是一个很旧版本的例子,在HelloWorldImpl.java中没有使用了extends RemoteServer,而在构造函数中是用UnicastRemoteObject.exportObject,按照作者的话说,是让初学者了解rmi的实现。
在Server.java中,现在最新的方法是使用java.rmi.registry..locateRegistry.createResitry(int port)来实现,这样就不必使用我在开题提到的运行rmiregistry命令来注册了,而是程序自动完成注册任务。(其实当我使用lacateRegistry可以正常运行,而使用rmiregistry命令则程序不能运行时,我一度以为是应为平台不同的原因造成的,所以我折腾了好久,结果原因确实上面提到的没有在class目录下运行该命令。不过这也从一个现实例子证明,java跟平台无关)。
这算是我学习rmi的开始,仅此分享成功的喜悦!