Equinox(OSGi)和JPA / Hibernate - 寻找实体

时间:2009-07-27 20:49:59

标签: spring hibernate equinox

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

    <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 for @Entities的时候,会发生异常,我不知道为什么。我已经包含了Hibernate正在吐出的日志的重要部分。

有没有人有任何想法我做错了什么或这里的问题是什么?

我正在使用:

  • Hibernate Core 3.3.0.SP1
  • Hibernate Annotations 3.4.0.GA
  • Hibernate Commons Annotations 3.1.0.GA
  • Hibernate EntityManager 3.4.0.GA
  • Equinox 3.4
  • Spring Dynamic Modules 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)

2 个答案:

答案 0 :(得分:5)

此博客shows how it can be handled与Spring的动态模块。 基于该博客,您将在应用程序上下文中为DAO和Service bean创建bean定义。 DAO引用了hibernate 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 Alliance blog。来自OSGi Alliance博客:

  

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

     

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

答案 1 :(得分:1)

之前的回复提到关于Hibernate和OSGi问题的OSGi博客文章是一个内容丰富的阅读。

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

OSGi是动态的

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

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

明确的依赖关系

OSGi需要明确连接依赖关系;如果你不导入一个包/包,那么你就看不到那些包/包中的类。

由于您说明确配置实体类是有效的,我假设您使用以下其中一项来进行依赖关系连接:

  • 导入级封装
  • 需要束
  • 动态导入
  • Equinox的好友政策

Rich Seller的建议应该有效(我还没有测试过),但你仍然被迫导入包含实体类的软件包,虽然我认为没有任何问题,所提议的解决方案提供了包扫描的选项,而不是明确指定每个实体类。

建议

  1. 使用Rich Seller的解决方案,但要注意解决方案不是动态的(这可能与您的应用无关)。
  2. 实现实体类的扩展程序模式,以便在实体提供程序包启动和停止时重新创建Hibernate会话工厂。
  3. 现在选项1很简单,选项2涉及大量工作。这完全取决于您需要从Hibernate自动添加/删除实体类而无需显式指定包/类。