4

我需要在 OSGi 包中公开基于 RMI 的系统。RMI 客户端“捆绑包”是一个 jar,我使用 bnd 工具将其转换为 OSGi 捆绑包(我无法访问源代码),至少在 eclipse 中一切似乎都很好,但是当我尝试连接到RMI 服务器,抛出 ClassCastException,很可能是因为 OSGi 和 RMI 对 ClassLoader 的使用很有趣。

我该如何解决这个问题?也许将 RMI 客户端 jar 用作“系统”捆绑包?

这是堆栈跟踪:

Blipnet OSGi 服务正在启动...
com.blipsystems.blipnet.api.blipserver.BlipServerConnectionException:连接到服务器时出现问题
    在 com.blipsystems.blipnet.api.core.blipserver.BlipServerConnectionAdapter.(​​未知来源)
    在 com.blipsystems.blipnet.api.core.blipserver.BlipServerConnectionAdapter.(​​未知来源)
    在 com.blipsystems.blipnet.api.blipserver.BlipServer.getConnection(未知来源)
    在 dk.itu.jingling.blipnetosgi.BlipnetConnectionService.setup(BlipnetConnectionService.java:28)
    在 dk.itu.jingling.blipnetosgi.BlipnetConnectionService.(BlipnetConnectionService.java:22)
    在 dk.itu.jingling.blipnetosgi.Activator.start(Activator.java:32)
    在 org.apache.felix.framework.util.SecureAction$Actions.run(SecureAction.java:1235)
    在 java.security.AccessController.doPrivileged(本机方法)
    在 org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:658)
    在 org.apache.felix.framework.Felix.activateBundle(Felix.java:1699)
    在 org.apache.felix.framework.Felix.startBundle(Felix.java:1621)
    在 org.apache.felix.framework.BundleImpl.start(BundleImpl.java:890)
    在 org.apache.felix.framework.BundleImpl.start(BundleImpl.java:877)
    在 org.apache.felix.fileinstall.internal.DirectoryWatcher.start(DirectoryWatcher.java:819)
    在 org.apache.felix.fileinstall.internal.DirectoryWatcher.start(DirectoryWatcher.java:805)
    在 org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:798)
    在 org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:299)
引起:java.lang.ClassCastException:com.blipsystems.blipnet.blipserver.cms.NewApiHandler_Stub 无法转换为 com.blipsystems.blipnet.api.core.blipserver.RemoteBlipServerConnection
4

2 回答 2

5

由于类可见性问题,标准 Java 序列化和 OSGi 不能很好地混合,并且 RMI 是建立在序列化之上的......

如果您四处搜索,您会发现很多人询问 RMI 和 OSGi,但很少有具体的解决方案。

我还没有坐下来研究 RMI 和 OSGi 的具体问题,但我确实解决了使用 Spring 的问题HTTPInvoker,它仍然使用 Java 的序列化机制。

问题归结为一个类:ObjectInputStream

这是负责反序列化的人 - 要反序列化一个对象,您需要对其类的可见性。如果您有一个现代 IDE,您可以查看此类的继承层次结构,并看到它有许多扩展,包括几个特定于 RMI 的类。

我的解决方案是使用 Spring 的可扩展实现ObjectInputStream并从我的包中插入类加载器,这样反序列化就可以访问可以看到我的类的类加载器。

您可以使用系统捆绑包,但这确实是一种黑客行为,我不建议长期使用它。

不幸的是,OSGi 仍然有一些令人讨厌的角落,需要您深入抽象层次才能找到问题并修复它——RMI 就是其中之一。

Paremus的家伙声称在他们的 Service Fabric 服务器产品(基于 OSGi 的服务器)中有一个 RMI 解决方案,并且可以配置为与 Felix 一起使用(我认为 Eclipse 的 Equinox 是默认的)。

于 2009-09-30T09:14:09.257 回答
0

我有同样的问题,我很惊讶它是多么容易解决。我有三个捆绑包:捆绑包A、捆绑包B、捆绑包C。bundleA - 一组抽象类,对 bundleB 和 bundleC 一无所知。BundleB 使用 bundleA 和 bundleC。bundleC 由 bundleB 使用。

所以,bundleA <-- bundleB --> bundleC

在 bundleA 中,我有调用 RMI 服务器并使用 bundleC 中的类的代码。在这里我遇到了一个问题——ClassNotFoundException。因此,我在 bundleA 类中使用了以下代码

ClassLoader threadClassLoader= Thread.currentThread().getContextClassLoader();
try {
    Class bundleCSomeClass = someVariablePassedFromBundleB.getMyClass();
    Thread.currentThread().setContextClassLoader(bundleCSomeClass.getClassLoader());
    //here we are calling RMI service
} catch (RemoteException ex) {

}finally{
    Thread.currentThread().setContextClassLoader(threadClassLoader);
}
于 2017-04-14T18:57:41.130 回答