使用rmi +插件时要做的特别事情

时间:2010-09-29 15:30:27

标签: java plugins rmi

我有一个应用FooApplicationfoo.jar中的代码),插件BarPluginfoo-bar-plugin.jar中的代码)。应用程序动态实例化插件的实例。它很棒。

FooApplication具有一些可通过RMI接口FooRemote访问的功能。除了一件事之外,这也很有效。 FooRemote有一个访问插件导出的Remote对象的方法,当我尝试将其中一个插件分发给RMI客户端时,我得到一个java.rmi.UnmarshalException。

public interface FooRemote extends Remote
{
    /* other methods */
    public RemoteControl getPluginRemoteControl(int i) throws RemoteException;
}
/** just a named Remote object for debugging purposes */
public interface RemoteControl extends Remote
{
    public String getName() throws RemoteException;
}

我在FooRemoteImpl中所做的工作如下:

/* just a test object */
private static class RC0 extends UnicastRemoteObject implements RemoteControl 
{
    public RC0() throws RemoteException { super(); }
    @Override public String getName() throws RemoteException { return "RC0"; }
}

@Override public RemoteControl getPluginRemoteControl(int i) 
       throws RemoteException 
{
    int j = i;
    if (j <= 0)
        return new RC0();

    Collection<RemoteControl> rclist = this.model.getApplicationPluginRemotes();
    for (RemoteControl rc : rclist)
    {
        if (--j == 0)
            return rc;
    }
    return null;
}

当我调用FooRemote.getPluginRemoteControl(0)时,它会发出我的虚拟类RC0的实例,并且可以从客户端正常工作。当我调用FooRemote.getPluginRemoteControl(1)时,它试图分发一个真正的插件遥控器,但它失败了:

??? Java exception occurred:
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
    java.lang.ClassNotFoundException: com.example.plugin.BarPluginRemoteControl (no security manager: RMI class loader disabled)

    at sun.rmi.server.UnicastRef.invoke(Unknown Source)

    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)

    at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)

    at $Proxy5.getPluginRemoteControl(Unknown Source)

Caused by: java.lang.ClassNotFoundException: com.example.plugin.BarPluginRemoteControl (no security manager: RMI class loader disabled)

[ more stuff deleted ] 

是什么给出了?

3 个答案:

答案 0 :(得分:2)

您可能需要设置SecurityManager。您的客户端无法找到类com.example.plugin.BarPluginRemoteControl,因为没有安全管理器可以访问它。

尝试以下方法:

向客户端代码添加:

System.setSecurityManager(new java.rmi.RMISecurityManager());

创建一个名为client.policy的策略文件,其中包含:

grant{
    permission java.security.AllPermission;
};

将策略文件传递到客户端的启动命令:

java -Djava.security.policy=client.policy  ... <main-class>...

答案 1 :(得分:2)

请不要将这些类放在RMI Registry类路径中。这解决了问题,但它不是正确的解决方案。这样做意味着每次更新服务器代码时,都需要将类与RMI Registry 和所有客户端同步。正确的解决方案是使用http或ftp URI在服务器的代码库上提供所需的类(请不要使用文件URI)。然后,RMI Registry和您的客户端将能够通过http或ftp动态访问所需的类。

您应该在代码库中包含的唯一类是服务器的远程接口,以及作为参数出现或从这些接口中的方法返回值的任何类,以及这些接口抛出的任何异常类。我相信(但我不确定)最好的做法是创建一个带有'-dl'后缀的单独jar,其中只包含这些类文件。

答案 2 :(得分:1)

如果您在单独的VM中运行它,RMI注册表还需要它自己的类路径上的类。我记得浪费太多时间学习这一点。

很高兴我能帮忙!

编辑:显然这不是正确的方法,请参阅评论者的回答。