我需要在OSGi包中公开一个基于RMI的系统。 RMI客户端“bundle”是一个jar,我使用bnd工具将其转换为OSGi包(我无法访问源代码),至少在eclipse中一切似乎都很好,但是当我尝试连接到RMI服务器抛出了ClassCastException,很可能是因为OSGi和RMI都很有趣地使用了ClassLoader。
我该如何解决这个问题?也许使用RMI客户端jar作为“系统”包?
这是堆栈跟踪:
Blipnet OSGi service starting... com.blipsystems.blipnet.api.blipserver.BlipServerConnectionException: There was a problem connecting to the server at com.blipsystems.blipnet.api.core.blipserver.BlipServerConnectionAdapter.(Unknown Source) at com.blipsystems.blipnet.api.core.blipserver.BlipServerConnectionAdapter.(Unknown Source) at com.blipsystems.blipnet.api.blipserver.BlipServer.getConnection(Unknown Source) at dk.itu.jingling.blipnetosgi.BlipnetConnectionService.setup(BlipnetConnectionService.java:28) at dk.itu.jingling.blipnetosgi.BlipnetConnectionService.(BlipnetConnectionService.java:22) at dk.itu.jingling.blipnetosgi.Activator.start(Activator.java:32) at org.apache.felix.framework.util.SecureAction$Actions.run(SecureAction.java:1235) at java.security.AccessController.doPrivileged(Native Method) at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:658) at org.apache.felix.framework.Felix.activateBundle(Felix.java:1699) at org.apache.felix.framework.Felix.startBundle(Felix.java:1621) at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:890) at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:877) at org.apache.felix.fileinstall.internal.DirectoryWatcher.start(DirectoryWatcher.java:819) at org.apache.felix.fileinstall.internal.DirectoryWatcher.start(DirectoryWatcher.java:805) at org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:798) at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:299) Caused by: java.lang.ClassCastException: com.blipsystems.blipnet.blipserver.cms.NewApiHandler_Stub cannot be cast to com.blipsystems.blipnet.api.core.blipserver.RemoteBlipServerConnection
答案 0 :(得分:5)
由于类可见性问题,标准Java序列化和OSGi混合不好,并且RMI建立在序列化之上......
如果你四处寻找,你会发现很多人都在询问有关RMI和OSGi的信息,但对于具体的解决方案却很少。
我没有坐下来调查RMI和OSGi的特殊问题,但我确实解决了使用Spring HTTPInvoker
的问题,它仍然使用Java的序列化机制。
问题归结为单个班级:ObjectInputStream
这是负责反序列化的人 - 并且要反序列化对象,您需要可以看到它的类。如果你有一个现代IDE,你可以查看这个类的继承层次结构,看看它有很多扩展,包括一些特定于RMI的类。
我的解决方案是使用Spring的ObjectInputStream
的可扩展实现并从我的bundle中插入类加载器,这样反序列化就可以访问可以看到我的类的类加载器。
你可以使用系统捆绑包,但这真的是一个黑客,我不建议它长期使用。
不幸的是,OSGi仍然有一些令人讨厌的角落,需要你深入挖掘抽象层次才能找到问题并修复它--RMI就是其中之一。
Paremus人声称他们的服务架构服务器产品(一个基于OSGi的服务器)的RMI解决方案,并且可以配置为与Felix一起使用(我认为Eclipse的Equinox是默认设置)。 / p>
答案 1 :(得分:0)
我遇到了同样的问题,我很惊讶它是如何轻易解决的。我有三个捆绑包:bundleA,bundleB,bundleC。 bundleA - 一组对bundleB和bundleC一无所知的抽象类。 BundleB使用bundleA和bundleC。 bundleB由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);
}