Java 使用rmi+;插件

Java 使用rmi+;插件,java,plugins,rmi,Java,Plugins,Rmi,我有一个应用程序FooApplication(在foo.jar中编码)和一个插件BarPlugin(在foo-bar plugin.jar中编码)。应用程序动态实例化插件的实例。它工作得很好 FooApplication具有一些可通过RMI接口访问的功能FooRemote。这也很有效,除了一件事FooRemote有一个方法来访问由插件导出的Remote对象,当我尝试将其中一个插件分发给rmi客户端时,我会得到一个java.rmi.unmarshaleException public interf

我有一个应用程序
FooApplication
(在
foo.jar
中编码)和一个插件
BarPlugin
(在
foo-bar plugin.jar中编码)。应用程序动态实例化插件的实例。它工作得很好

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

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;
}

提供了什么?

您可能需要设置一个
安全管理器。您的客户端找不到类
com.example.plugin.BarPluginRemoteControl
,因为没有安全管理器授予它访问权限

请尝试以下操作:

/* 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;
}
在客户端代码中添加:

System.setSecurityManager(new java.rmi.RMISecurityManager());
创建名为
client.policy
的策略文件,其中包含:

grant{
    permission java.security.AllPermission;
};
将策略文件传递到客户端的启动命令:

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

您可能需要设置一个
SecurityManager
。您的客户端找不到类
com.example.plugin.BarPluginRemoteControl
,因为没有安全管理器授予它访问权限

请尝试以下操作:

/* 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;
}
在客户端代码中添加:

System.setSecurityManager(new java.rmi.RMISecurityManager());
创建名为
client.policy
的策略文件,其中包含:

grant{
    permission java.security.AllPermission;
};
将策略文件传递到客户端的启动命令:

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

RMI注册表还需要它自己的类路径上的类,以防您在单独的VM中运行它。我记得我花了太多的时间在艰苦的学习上

很高兴我能帮忙


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

RMI注册表也需要在其自己的类路径上的类,以防您在单独的VM中运行它。我记得我花了太多的时间在艰苦的学习上

很高兴我能帮忙


编辑:显然这不是正确的方法,请参见评论员的答案。

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


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

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


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

RMI注册表也需要在其自己的类路径上使用这些类,以防您在单独的VM中运行它。darri:这就是问题所在。(作为一个单独的答案发布,我会接受)不过,你也应该有一个安全经理。为了进行测试,请使用AllPermission,然后再调整到尽可能小的权限集(除非您在安全性良好的LAN上,然后我会说坚持使用AllPermission)。RMI注册表还需要在其自己的类路径上使用这些类,以防您在单独的VM中运行。darri:这就是问题所在。(作为一个单独的答案发布,我会接受)不过,你也应该有一个安全经理。为了进行测试,请使用AllPermission,然后再调整到尽可能小的权限集(除非您在安全良好的LAN上,然后我会说坚持使用AllPermission)。请查看我的回答。这并不能解决问题,但它是一种解决方法。请参阅我的回复。这并不能解决问题,但它是一个解决方法。感谢您的帮助,我们已经注意到了这一点+谢谢你的好意。然而,在我的情况下,这不适用;我正在运行服务器(
java-jar myjar.jar
)和客户机(MATLAB,classpath设置为myjar.jar)在同一台机器上的同一个位置上运行同一个.jar文件,所以根据定义,当服务器更新时,客户机也会这样做。希望我没有让任何人感到厌烦。我刚刚接触RMI时,在像您现在这样在本地开发和测试之后,在迁移到更分布式的设置时,我消耗了很多周期。您仍然不需要为RMI注册表设置类路径。我建议您的代码库至少使用一个file:URI(仅在本地工作)。通过网络时切换到ftp或http。如果您继续使用RMI,我保证为注册表设置一个类路径会烧掉您。谢谢您,我们已经注意到了+谢谢你的好意。就我而言