4

我正在尝试在 OSGi (Equinox) 环境中使用 Hibernate/Spring。如果我明确地将它指向 Persistence.xml 中的实体类,它会很好用:

    <class>com.es.t.eee.domain.StuffSource</class>
    <class>com.es.t.eee.domain.PostalAddress</class>

我想要的是让 Hibernate 像在 OSGi 环境之外那样“找到”所有实体类。

Hibernate 正在寻找 @Entities 的正确包:

Searching mapped entities in jar/par: bundleresource://34/
WARN  27-07 15:30:24,235 (InputStreamZippedJarVisitor.java:doProcessElements:41):
Unable to find file (ignored): bundleresource://34/

看起来它应该可以工作,但是当它在 Bundle Jar 中查找 @Entities 时,会发生异常,我不知道为什么。我已经包含了 Hibernate 吐出的日志的重要部分。

有谁知道我做错了什么或这里的问题是什么?

我在用:

  • 休眠核心 3.3.0.SP1
  • 休眠注释 3.4.0.GA
  • Hibernate Commons 注释 3.1.0.GA
  • 休眠实体管理器 3.4.0.GA
  • 春分 3.4
  • Spring 动态模块 1.2.0

这是 Hibernate 解析 Persistence.xml 的地方

INFO  27-07 15:30:24,110 (Version.java:<clinit>:15):
Hibernate Annotations 3.4.0.GA
INFO  27-07 15:30:24,110 (Environment.java:<clinit>:543):
Hibernate 3.3.0.SP1
INFO  27-07 15:30:24,110 (Environment.java:<clinit>:576):
hibernate.properties not found
INFO  27-07 15:30:24,126 (Environment.java:buildBytecodeProvider:709):
Bytecode provider name : javassist
INFO  27-07 15:30:24,126 (Environment.java:<clinit>:627):
using JDK 1.4 java.sql.Timestamp handling
INFO  27-07 15:30:24,157 (Version.java:<clinit>:14):
Hibernate Commons Annotations 3.1.0.GA
INFO  27-07 15:30:24,157 (Version.java:<clinit>:16):
Hibernate EntityManager 3.4.0.GA
DEBUG 27-07 15:30:24,219 (Ejb3Configuration.java:configure:312):
Processing PersistenceUnitInfo [
    name: unit.postgresql
    persistence provider classname: null
    classloader: BundleDelegatingClassLoader for [DatabaseObjects (DatabaseObjects)]
    Temporary classloader: org.springframework.instrument.classloading.SimpleThrowawayClassLoader@11b50a1
    excludeUnlistedClasses: true
    JTA datasource: null
    Non JTA datasource: com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 1000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1012f6d821goxcok12zcw86|174f02c, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> org.postgresql.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1012f6d821goxcok12zcw86|174f02c, idleConnectionTestPeriod -> 0, initialPoolSize -> 5, jdbcUrl -> jdbc:postgresql://localhost:5432/test2, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 100, maxStatements -> 100, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
    Transaction type: RESOURCE_LOCAL
    PU root URL: bundleresource://34/
    Jar files URLs []
    Managed classes names []
    Mapping files names []
    Properties [
        hibernate.default_batch_fetch_size: 500
        hibernate.cache.provider_class: net.sf.ehcache.hibernate.EhCacheProvider
        hibernate.dialect: org.hibernate.dialect.PostgreSQLDialect
        hibernate.max_fetch_depth: 5
        hibernate.query.factory_class: org.hibernate.hql.ast.ASTQueryTranslatorFactory
        hibernate.format_sql: false
        hibernate.jdbc.batch_size: 1000
        hibernate.use_outer_join: true
        hibernate.archive.autodetection: class
        hibernate.show_sql: false
        hibernate.bytecode.provider: cglib]

这是发生错误的地方,因为它试图找到实体:

DEBUG 27-07 15:30:24,235 (Ejb3Configuration.java:getDetectedArtifacts:562):
Detect class: true; detect hbm: false
DEBUG 27-07 15:30:24,235 (Ejb3Configuration.java:getDetectedArtifacts:562):
Detect class: true; detect hbm: false
DEBUG 27-07 15:30:24,235 (AbstractJarVisitor.java:unqualify:116):
Searching mapped entities in jar/par: bundleresource://34/
WARN  27-07 15:30:24,235 (InputStreamZippedJarVisitor.java:doProcessElements:41):
Unable to find file (ignored): bundleresource://34/
java.lang.NullPointerException: in is null
    at java.util.zip.ZipInputStream.<init>(Unknown Source)
    at java.util.jar.JarInputStream.<init>(Unknown Source)
    at java.util.jar.JarInputStream.<init>(Unknown Source)
    at org.hibernate.ejb.packaging.InputStreamZippedJarVisitor.doProcessElements(InputStreamZippedJarVisitor.java:37)
    at org.hibernate.ejb.packaging.AbstractJarVisitor.getMatchingEntries(AbstractJarVisitor.java:139)
    at org.hibernate.ejb.Ejb3Configuration.addScannedEntries(Ejb3Configuration.java:287)
    at org.hibernate.ejb.Ejb3Configuration.scanForClasses(Ejb3Configuration.java:614)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:360)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:131)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:224)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:291)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isSingleton(AbstractBeanFactory.java:366)
    at org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean.afterPropertiesSet(OsgiServiceFactoryBean.java:235)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:423)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
    at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext.completeRefresh(AbstractDelegatedExecutionApplicationContext.java:288)
    at org.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor$CompleteRefreshTask.run(DependencyWaiterApplicationContextExecutor.java:145)
    at java.lang.Thread.run(Unknown Source)
4

2 回答 2

5

这个博客展示了如何使用 Spring 的动态模块来处理它。根据该博客,您将在应用程序上下文中为 DAO 和服务 bean 创建 bean 定义。DAO 引用了休眠 sessionFactory bean:

<bean id="stuffDao" class="com.es.t.eee.domain.dao.StuffSourceDaoImpl">
  <property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="stuffService" 
  class="com.es.t.eee.domain.dao.StuffServiceImpl">
  <property name="stuffDao" ref="stuffDao"/>
</bean>

<bean id="stuffSource" 
  class="com.es.t.eee.domain.StuffSource" scope="prototype"/>

StuffSourceDaoImpl 将实现 store() 方法来持久化 StuffSource,它将 StuffSource 传递给 HibernateTemplate 以实际执行持久化。

为了避免必须定义 persistence.xml 文件或指定每个实体,您可以使用 AnnotationSessionFactoryBean 和通配符来包含包含您的实体的包中的所有类型(您可能想要设置 packagesToScan 属性,我已经没有尝试过,它可能会让你回到原来的问题):

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
  <property name="hibernateProperties">
    <props>
      <!--etc-->
    </props>
  </property>
  <!-- set either one of these properties -->
  <property name="annotatedClasses">
    <list>
      <value>com.es.t.eee.domain.StuffSource</value>
      <value>com.es.t.eee.domain.PostalAddress</value>
    </list>
  </property>
  <property name="packagesToScan">
    <list>
      <value>com.es.t.eee.domain</value>
    </list>
  </property>
</bean>

要使用它,您将获得 BundleContext,从上下文中获取服务和 bean,然后照常进行:

String serviceName = StuffService .class.getName();
StuffService service = 
  (StuffService )context.getService(context.getServiceReference(serviceName));

String stuffName = StuffSource.class.getName();
StuffSource stuffSource = 
  (StuffSource) context.getService(context.getServiceReference(stuffName ));

//do whatever with StuffSource
...

service.store(stuffSource );

您可能还想查看此OSGi 联盟博客,该博客讨论了所涉及的一些问题。来自 OSGi 联盟博客:

Hibernate 操纵类路径,这样的程序通常不能很好地与基于 OSGi 的系统一起工作。原因是在许多系统中,模块之间的类可见性或多或少是不受限制的。在 OSGi 框架中,类路径被很好地定义和限制。这给了我们很多好的特性,但是当我们想要使用一个希望在它长大后成为类加载器的库时,它也给我们带来了痛苦。...

要使用 Hibernate,您需要一个 Session 对象。您可以从 SessionFactory 获取 Session 对象。要获取 SessionFactory,您需要使用 Configuration 对象来创建它。配置对象是从配置 XML 文件创建的。默认情况下,Hibernate 从 JAR 文件的根目录加载它,但是,如果需要,您可以手动将类添加到配置中。

于 2009-07-30T18:24:19.330 回答
1

前面提到的关于 Hibernate 和 OSGi 问题的 OSGi 博客条目的回复是一个信息性阅读。

我建议退后一步,思考在传统 Java 应用程序中正确的假设,以及它们在 OSGi 中如何不再有效:

OSGi 是动态的

如果在提供实体类的任何包之前启动 Hibernate 包,您的应用程序将如何工作?即使扫描实体类有效,它也找不到任何实体类。

在传统 Java 中,由于扁平类路径,所有类在启动时都可用,但在 OSGi 中,只有在启动贡献包并导入包时,类才可用。

显式依赖

OSGi 需要明确的依赖关系;如果您不导入包/包,那么您将看不到这些包/包中的类。

既然您说显式配置实体类是有效的,我假设您正在使用以下方法之一来进行依赖连接:

  • 进口包装
  • 要求捆绑
  • 动态导入
  • Equinox 的伙伴政策

Rich Seller 的建议应该可行(我还没有测试过),但是您仍然被迫导入包含实体类的包,尽管我认为这没有任何问题,并且建议的解决方案提供了包扫描选项,而不是明确指定每个单个实体类。

建议

  1. 使用 Rich Seller 的解决方案,但请注意该解决方案不是动态的(这对您的应用程序可能无关紧要)。
  2. 为实体类实现扩展器模式,以便您可以在实体贡献包启动和停止时重新创建 Hibernate 会话工厂。

现在选项 1 很简单,选项 2 涉及大量工作。这完全取决于您对从 Hibernate 中自动添加/删除实体类的要求,而无需显式指定包/类。

于 2009-08-02T10:22:34.377 回答