Hibernate、JDBC 驱动程序和 OSGi 问题
我遇到了一个有点令人沮丧的问题。 我使用 Apache Felix 作为我的 OSGi 框架,并且还使用 Hibernate 来解决持久性问题。
我使用 Hibernate 的“osgi-bundle”版本(com.springsource.org.hibernate-3.2.6.ga.jar)。 据我所知,这是 Hibernate Core,在 META-INF/MANIFEST.mf 中安装了一些额外的 osgi-metdata。 此信息(包导出和包导入)对于 osgi 系统至关重要。
我的问题是 Hibernate 包找不到我的 JDBC 驱动程序。 将Import语句添加到springsource Hibernate包中感觉非常错误。 一定有更好的方法来解决这个问题。
I'v encountered a somewhat frustating problem.
Im using Apache Felix as my OSGi framework and Im also using Hibernate for persistency issues.
Im using the "osgi-bundle" version of Hibernate (com.springsource.org.hibernate-3.2.6.ga.jar). As far as I know this is the Hibernate Core with some additional osgi-metdata installed in the META-INF/MANIFEST.mf. This information (Package-Export and Package-Import) is vital for osgi systems.
My problem is that the Hibernate bundle cant find my JDBC-drivers. It feels very wrong to add Import statements to the springsource Hibernate bundle. There must be some better way to solve this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Hibernate 并不是一个很好的 OSGi 公民,因为 Hibernate 对类可见性所做的许多假设在 OSGi 容器中不再成立。
使用
Class.forName()
加载 JDBC 驱动程序的常用方法在 OSGi 中不起作用,因为在这种情况下,Hibernate 将尝试加载驱动程序,但不会找到它,因为 Hibernate 不(也不应该)导入 JDBC 驱动程序包。JDBC 驱动程序管理器还尝试通过确定调用类的类加载器是否应该看到驱动程序来变得聪明,这也与 OSGi 冲突。
如果您使用 Spring 配置 Hibernate,那么我建议您使用 SimpleDriverDataSource 类,因为它在 OSGi 中工作,并且 Spring 允许您使用具体的数据源配置 Hibernate,而不是传递 Hibernate 需要实例化的类名。
一旦解决了这个问题,您可能会遇到 Hibernate 看不到域类的问题。 我只有 XML 映射方法的经验,我认为 OSGi 更简单,因为我认为注释方式需要某种 AOP 编织,这是 OSGi 当前的另一个痛点。
目前,除非您使用 Spring 的 dm Server 之类的东西,否则您需要更加熟悉 Java 的类加载机制以及如何使用 OSGi 的服务方法来解决普通 Java 和 OSGi 世界之间的不兼容性。
具体来说,研究企业库如何使用上下文类加载器以及如何管理它。 我使用 Spring dm 将遗留代码包装在 OSGi 服务中,因为这样可以轻松控制上下文类加载器。
Hibernate isn't a very good OSGi citizen as many of the assumptions Hibernate makes on class visibility are no longer true in an OSGi container.
The usual way of loading JDBC drivers with the
Class.forName(<jdbc class name>)
doesn't work inside OSGi because, in this case, Hibernate will try and load the driver but won't find it as Hibernate doesn't (and shouldn't) import the JDBC driver package.The JDBC driver manager also tries to be smart by working out whether the calling class' class loader should see the driver and this also conflicts with OSGi.
If you use Spring to configure Hibernate then I suggest you use the
SimpleDriverDataSource
class as this works in OSGi and Spring allows you to configure Hibernate with a concrete data source rather than passing a class name that Hibernate needs to instantiate.Once you get past that problem you'll probably run into the issues of Hibernate not seeing your domain classes. I only have experience with the XML mapping approach, with I think is simpler in OSGi as I think the annotations way requires AOP weaving of some sort and that's another current pain-point with OSGi.
At the moment, unless you use something like Spring's dm Server you'll need to become much more familiar with Java's class loading mechanism and how you can use OSGi's approach to services to work around the incompatibilities between vanilla Java and the OSGi world.
Specifically, look into how enterprise libraries use the context class loader and how you can manage this. I am using Spring dm to wrap legacy code in OSGi services as this makes it easy to control the context class loader.
您是否处理了正确的捆绑开始订购? 有一种方法可以设置每个包的启动级别,以便您的系统可以正确引导。 如果某些激活器尝试直接获取服务,则可能需要正确的捆绑包启动级别。 如果服务不可用,服务消费者就会陷入困境。
尝试为您的捆绑包设置正确的启动级别,看看它是否有效。 具体来说,您必须先启动包含 JDBC 驱动程序的捆绑包,然后再启动 hibernate 捆绑包。
另一个问题可能是您有一些未解决的依赖关系。 确保一切都在那里。 您可以通过获取 OSGi 控制台并请求服务列表来做到这一点。 在 Equinox 中,这可以归结为 OSGi shell 中的 -console 命令行参数和“ss”后跟“diag”命令。
编辑(回答您的评论):
驱动程序是通过其接口注册的。 然后 Hibernate 可能会通过其接口查找驱动程序,无需导入特定的驱动程序类。 无论如何,这都会引入对特定于实现的类的不期望的依赖。
Did you take care of the correct bundle start ordering? There is a way to set the start level of every bundle, so that your system can bootstrap correctly. The correct start level of bundles might be required if some activators try to get services directly. In case the services are not available, the service consumers will just be stuck.
Try to set the proper start levels for your bundles and see whether it works. Concretely you would have to start the bundle with the JDBC drivers first before the hibernate bundle.
Another problem might be that you have some unsolved dependencies. Make sure that everythingg is there. You can do this by getting an OSGi console and asking for a list of services. In Equinox this boils down to the -console commandline argument and the "ss" followed by "diag" commands in the OSGi shell.
EDIT (answer to your comment):
The drivers are registerd by their interface. Hibernate then probably looks up a driver by its interface, no need to import specific driver classes. This anyway would introduce an undesired dependency on an implementation specific class.
在 OSGi 包中,您只能看到已导入的包中的类和资源。 Hibernate 包不会(也不应该)导入您的域类。 因此,当 Hibernate 尝试处理 XML 映射文件时,它会抱怨找不到正在映射的类(您的域类)。
我们通过使用 Equinox 的伙伴策略来解决这个问题,因此每个提供域对象的包都是 Hibernate 的类加载伙伴。 我不太喜欢这种方法,但我没有时间编写我脑海中的(希望如此)优雅的解决方案。
正如我在之前的文章中所说,对于 Hibernate 而言,操作上下文类加载器可能是最好的长期选择。
In an OSGi bundle you can only see classes and resources from packages you have imported. The Hibernate bundle doesn't (and shouldn't) import your domain classes. Therefore, when Hibernate tries to process an XML mapping file it will complain that it can't find the class that is being mapped (your domain class).
We get around the problem by using Equinox's buddy policy so every bundle that supplies domain objects is a class-loading buddy of Hibernate. I don't like this approach too much, but I don't have the time to write the (hopefully) elegant solution that's in my head.
As I said in my earlier post, manipulating the context class loader is probably the best long-term bet when it comes to Hibernate.
我遇到过类似问题 不久前。 解决方案是将 jdbc-provider 包和 jdbc-user 包注册为“伙伴”。 这是因为一个包不能在没有明确声明的情况下使用另一个包中的类(因此 jdbc 驱动程序也是如此)。 这是针对 Eclipse 的,所以我认为它可能对您有所帮助。
I've encountered similar problem a while ago. The solution was to register jdbc-provider bundle and jdbc-user bundles as "buddies". This is because one bundle can't use classes (so jdbc drivers too) from another without explicitly declaring it. This was for Eclipse, so I assume it may help you.
我还没有尝试过这个(因为我反对 RDBMS,因此也反对 ORM),但一种解决方案可能是使用 OSGi 片段。
创建一个包含域类的片段,并将 Hibernate 包指定为主机。 该片段应该导出您的域类的包。
同样,您可以对要使用的 JDBC 驱动程序执行相同的操作。 获取驱动程序类并将它们转换为 OSGi 片段,并使用 Hibernate 作为主机包。 但是,您不必导出驱动程序的包,因为它们仅由 Hibernate 包使用。
我怀疑 Felix 在 9 个月前还没有完全支持 Fragment,但现在看来确实是这样:
http://osgithoughts.blogspot.com/ 2009/09/felix-now-complete-supports-osgi-fragments.html
I haven't tried this (as I'm anti-RDBMS and thus anti-ORM as well), but one solution might be to use OSGi fragments.
Create a fragment that contains your domain classes and specify the Hibernate bundle as the host. This fragment should export the packages of your domain classes.
Likewise, you can do the same thing for the JDBC driver you want to use. Take the driver classes and turn them in to an OSGi fragment with Hibernate as the host bundle. However, you don't have to export the driver's packages since they are only going to be used by the Hibernate bundle.
I suspect fragments weren't supported in full by Felix 9 months ago, but they certainly are now it seems:
http://osgithoughts.blogspot.com/2009/09/felix-now-fully-supports-osgi-fragments.html