Hibernate、JDBC 驱动程序和 OSGi 问题
Posted
技术标签:
【中文标题】Hibernate、JDBC 驱动程序和 OSGi 问题【英文标题】:Hibernate, JDBC-driver and OSGi problem 【发布时间】:2010-10-15 12:03:50 【问题描述】:我遇到了一个有点令人沮丧的问题。 我使用 Apache Felix 作为我的 OSGi 框架,我还使用 Hibernate 来解决持久性问题。
我正在使用 Hibernate 的“osgi-bundle”版本(com.springsource.org.hibernate-3.2.6.ga.jar)。据我所知,这是 Hibernate Core,在 META-INF/MANIFEST.mf 中安装了一些额外的 osgi-metdata。此信息(Package-Export 和 Package-Import)对于 osgi 系统至关重要。
我的问题是 Hibernate 包找不到我的 JDBC 驱动程序。在springsource Hibernate bundle中加入Import语句感觉很不对劲。一定有更好的方法来解决这个问题。
【问题讨论】:
【参考方案1】:Hibernate 并不是一个很好的 OSGi 公民,因为 Hibernate 对类可见性所做的许多假设在 OSGi 容器中不再成立。
使用Class.forName(<jdbc class name>)
加载 JDBC 驱动程序的常用方法在 OSGi 中不起作用,因为在这种情况下,Hibernate 会尝试加载驱动程序但不会找到它,因为 Hibernate 不会(也不应该) ) 导入 JDBC 驱动包。
JDBC 驱动程序管理器还试图通过计算调用类的类加载器是否应该看到驱动程序来变得聪明,这也与 OSGi 冲突。
如果您使用 Spring 来配置 Hibernate,那么我建议您使用 SimpleDriverDataSource
类,因为这适用于 OSGi,并且 Spring 允许您使用具体的数据源来配置 Hibernate,而不是传递 Hibernate 需要实例化的类名。
一旦你解决了这个问题,你可能会遇到 Hibernate 看不到你的域类的问题。我只有 XML 映射方法的经验,我认为在 OSGi 中更简单,因为我认为注释方式需要某种 AOP 编织,这是 OSGi 当前的另一个痛点。
目前,除非您使用 Spring 的 dm Server 之类的东西,否则您需要更加熟悉 Java 的类加载机制以及如何使用 OSGi 的服务方法来解决 vanilla Java 和 OSGi 世界之间的不兼容问题.
具体来说,研究企业库如何使用上下文类加载器以及如何管理它。我正在使用 Spring dm 将遗留代码包装在 OSGi 服务中,因为这样可以轻松控制上下文类加载器。
【讨论】:
【参考方案2】:您是否处理了正确的捆绑包开始订购?有一种方法可以设置每个包的启动级别,以便您的系统可以正确引导。如果某些激活器尝试直接获取服务,则可能需要正确的捆绑包启动级别。如果服务不可用,服务消费者就会被卡住。
尝试为您的捆绑包设置正确的启动级别,看看它是否有效。具体来说,您必须先使用 JDBC 驱动程序启动该包,然后再使用休眠包。
另一个问题可能是您有一些未解决的依赖项。确保一切都在那里。您可以通过获取 OSGi 控制台并询问服务列表来完成此操作。在 Equinox 中,这归结为 -console 命令行参数和 OSGi shell 中后跟“diag”命令的“ss”。
编辑(回答您的评论):
驱动程序通过其接口注册。然后 Hibernate 可能通过其接口查找驱动程序,无需导入特定的驱动程序类。无论如何,这会引入对实现特定类的不希望的依赖。
【讨论】:
但我看不到休眠包如何在不显式导入的情况下找到正确的 jdbc 驱动程序,例如。 org.embedded.derby 或 org.mysql.jdbc.. 你有你的休眠包的来源吗?看看清单,看看哪个是激活器类。然后看看这个类,这可能会回答你的问题 "Hibernate 然后可能通过其接口查找驱动程序,无需导入特定的驱动程序类"。这是否意味着 Hibernate 包有一些用于设置特定 JDBC 驱动程序的 API? (例如,设置 mysql-jdbc、设置 oracle-jdbc 等。否则我无法看到 hibernate 如何获取正确的驱动程序) 驱动程序提供者注册他的驱动程序(ctx.register(JDBCDriver, MySQLJDBCDriver) 并且需要它的人在不直接知道驱动程序的情况下请求驱动程序(ctx.getService(JDBCDriver))【参考方案3】:在 OSGi 包中,您只能查看已导入包中的类和资源。 Hibernate 包不会(也不应该)导入您的域类。因此,当 Hibernate 尝试处理 XML 映射文件时,它会抱怨找不到正在映射的类(您的域类)。
我们通过使用 Equinox 的伙伴策略解决了这个问题,因此每个提供域对象的包都是 Hibernate 的类加载伙伴。我不太喜欢这种方法,但我没有时间编写我脑海中的(希望如此)优雅的解决方案。
正如我在之前的文章中所说,对于 Hibernate 而言,操作上下文类加载器可能是最好的长期选择。
【讨论】:
【参考方案4】:我不久前遇到过similar problem。解决方案是将 jdbc-provider bundle 和 jdbc-user bundle 注册为“buddies”。这是因为一个捆绑包不能使用来自另一个捆绑包的类(所以 jdbc 驱动程序也是如此),除非明确声明它。这是针对 Eclipse 的,所以我认为它可能会对您有所帮助。
【讨论】:
【参考方案5】:我还没有尝试过(因为我是反 RDBMS,因此也是反 ORM),但一种解决方案可能是使用 OSGi 片段。
创建一个包含您的域类的片段并将 Hibernate 包指定为主机。此片段应导出您的域类的包。
同样,您可以对要使用的 JDBC 驱动程序执行相同的操作。获取驱动程序类并将它们转换为以 Hibernate 作为主机包的 OSGi 片段。但是,您不必导出驱动程序包,因为它们只会被 Hibernate 包使用。
我怀疑 9 个月前 Felix 没有完全支持 Fragments,但现在看来它们肯定是: http://osgithoughts.blogspot.com/2009/09/felix-now-fully-supports-osgi-fragments.html
【讨论】:
OSGi 人员的建议是不要使用碎片沿着这条路线走,并将它们限制在最初的意图中。这些问题都可以在不使用片段的情况下解决。 EclipseLink 的人对此做了一个有趣的演示(现在不记得链接了)。以上是关于Hibernate、JDBC 驱动程序和 OSGi 问题的主要内容,如果未能解决你的问题,请参考以下文章
如何让 Spring JPA、Hibernate 和 OSGi 发挥出色?
Equinox OSGi + JPA Eclipselink + PAX JDBC 驱动适配器
osgi spring hibernate virgo example ClassNotFoundException: org.hibernate.cfg.Configuration
具有运行时 pojos 的带有 Hibernate 的 OSGi 片段包
使用 Hibernate Unmanaged JPA 在 Equinox OSGI 框架中获取 EntityManagerFactory