2013-07-19 62 views
4

当我在那里,我想设置JPA的应用程序上下文找到持久化单元:春天,JPA,休眠,Tomcat的:无法加载Spring应用程序上下文

应用程序的context.xml

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"> 
    <property name="persistenceUnits"> 
     <map> 
      <entry key="pu1" value="pu1" /> 
      <entry key="pu2" value="pu2" /> 
     </map> 
    </property> 
    <property name="defaultPersistenceUnitName" value="pu1" /> 
</bean> 

<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
      <property name="showSql" value="true" /> 
      <property name="generateDdl" value="false" /> 
      <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" /> 
     </bean> 
    </property> 
    <property name="persistenceUnitName" value="pu1" /> 
    <property name="dataSource" ref="dataSource1" /> 
</bean> 

<bean id="emf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
      <property name="showSql" value="true" /> 
      <property name="generateDdl" value="false" /> 
      <property name="databasePlatform" value="org.hibernate.dialect.SQLServer2005Dialect" /> 
     </bean> 
    </property> 
    <property name="persistenceUnitName" value="pu2" /> 
    <property name="dataSource" ref="dataSource2" /> 
</bean> 

<!-- Enable annotation style of managing transactions --> 
<tx:annotation-driven /> 

<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="emf1" /> 
    <property name="dataSource" ref="dataSource1" /> 
</bean> 

<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="emf2" /> 
    <property name="dataSource" ref="dataSource2" /> 
</bean> 

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
    <property name="locations"> 
     <list> 
      <value>classpath:config/db/database.properties</value> 
     </list> 
    </property> 
    <property name="ignoreUnresolvablePlaceholders" value="true" /> 
    <property name="ignoreResourceNotFound" value="true" /> 
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/> 
</bean> 

<!-- The actual config of the database is read from the properties file database.properties --> 
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" 
    p:acquireIncrement="5" p:idleConnectionTestPeriod="14400" p:maxPoolSize="50" p:maxStatements="15" 
    p:minPoolSize="5" p:testConnectionOnCheckout="true" p:preferredTestQuery="SELECT 4;" 
    p:driverClass="${db.system1.driver}" p:jdbcUrl="${db.system1.url}" p:user="${db.system1.user}" p:password="${db.system1.password}" /> 

<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:acquireIncrement="5" p:idleConnectionTestPeriod="60" p:maxPoolSize="10" 
    p:maxStatements="50" p:minPoolSize="3" p:testConnectionOnCheckout="true" p:preferredTestQuery="SELECT 4;" 
    p:driverClass="${db.system2.driver}" p:jdbcUrl="${db.system2.url}" p:user="${db.system2.user}" p:password="${db.system2.password}" /> 

<context:annotation-config /> 
<context:component-scan base-package="com.myapp.model.manager"/> 

的persistence.xml

<persistence-unit name="pu1" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 
    <class>com.myapp.model.Address</class> 
    <class>com.myapp.model.AgressoFile</class> 
    <class>com.myapp.model.CustomerGroup</class> 
    ... 
</persistence-unit> 

<persistence-unit name="pu2" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 
    <class>com.myapp.model.CompetenceArea</class> 
    <class>com.myapp.model.CompetenceAreaCategory</class> 
    ... 
</persistence-unit> 

我加载应用程序上下文在的web.xml这样:

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
     /WEB-INF/spring/application-context.xml 
    </param-value> 
</context-param> 

<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

CompetenceAreaManager类,定位在扫描包 “com.myapp.model.manager” 有如下内容:

@Service 
public class CompetenceAreaManager { 

    @PersistenceUnit(unitName = "pu2") 
    private EntityManagerFactory entityManagerFactory; 

    @SuppressWarnings("unchecked") 
    public List<CompetenceArea> getCompetenceAreas() { 
     List<CompetenceArea> competenceAreaList = null; 
     EntityManager em = entityManagerFactory.createEntityManager(); 
     Query q = em.createNamedQuery(CompetenceArea.FIND_ALL); 
     competenceAreaList = q.getResultList(); 
     return competenceAreaList; 
    } 

    public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) { 
     this.entityManagerFactory = entityManagerFactory; 
    } 
} 

然而,当我尝试运行在Tomcat 7.0中的应用程序,我得到以下错误:

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'competenceAreaManager': Injection of persistence dependencies failed; nested exception is java.lang.IllegalStateException: Could not obtain EntityManagerFactory [pu2] from JNDI 
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:343) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1122) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) 
    ... 
Caused by: java.lang.IllegalStateException: Could not obtain EntityManagerFactory [pu2] from JNDI 
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.getPersistenceUnit(PersistenceAnnotationBeanPostProcessor.java:435) 
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:643) 
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:637) 
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150) 
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) 
    ... 
Caused by: javax.naming.NameNotFoundException: Name [pu2] is not bound in this Context. Unable to find [pu2]. 
    at org.apache.naming.NamingContext.lookup(NamingContext.java:820) 
    at org.apache.naming.NamingContext.lookup(NamingContext.java:168) 
    at org.apache.naming.SelectorContext.lookup(SelectorContext.java:158) 
    at javax.naming.InitialContext.lookup(Unknown Source) 
    at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:154) 
    ... 

任何想法wha我做错了吗?

回答

2

如果使用persistenceUnits配置PersistenceAnnotationBeanPostProcessor,则通知PersistenceAnnotationBeanPostProcessor PU来自JNDI(如setPersistenceUnits()方法的javadoc所述)。堆栈跟踪实际上显示失败的JNDI查找。

因为您在application-context.xml中使用<context:annotation-config/>,所以不需要声明PersistenceAnnotationBeanPostProcessor,因为将自动注册一个PersistenceAnnotationBeanPostProcessor,它通过读取位于其中的META-INF/persistence.xml文件来查找PU类路径,这实际上是你所期望的。

你的配置应该是如此简单:

的persistence.xml保持不变

CompetenceAreaManager

正如谢尔盖·马卡罗夫提到它,只是注入的EntityManager与@PersistenceContext,而不是注入带@PersistenceUnit的EntityManagerFactory。 em是事务性的(因此绑定到线程,从而确保DAO的线程安全),并且仍然可以使用unitName配置@PersistenceContext以指定EM必须绑定到的PU。

应用程序的context.xml

刚落PersistenceAnnotationBeanPostProcessor bean的声明。文件的其余部分保持不变。

我还没有试过你的特定配置(2 PU),但我提到的配置是我一直使用的配置,并取得了成功。

+0

非常感谢您的回答和详细解释!它像一个魅力一样工作! :) – kotinuka

1

据我了解,从我最近在同一个应用程序中设置2个EntityManagerFactory的角度来看,@PersistenceUnit(unitName =“myPU”)根本不起作用。

我建议注入EntityManager而不是EntityManagerFactory。这是很清楚的,因为你总是知道使用哪个EMF。指定正确的TransactionManager相同。

更新的服务类代码:

@Service 
public class CompetenceAreaManager 
{ 
    @PersistenceContext(unitName = "emf1") 
    private EntityManager em; 

    @SuppressWarnings("unchecked") 
    @Transactional(transactionManager="transactionManager1", readOnly=true) 
    public List<CompetenceArea> getCompetenceAreas() 
    { 
     List<CompetenceArea> competenceAreaList = null; 
     Query q = em.createNamedQuery(CompetenceArea.FIND_ALL); 
     competenceAreaList = q.getResultList(); 
     return competenceAreaList; 
    } 
} 

这种注射液是安全的,因为春天注入的EntityManager的一个代理,从而保证线程安全。

+0

谢谢您的回复!如果我将这些行从应用程序上下文移动到DispatherServlet的servlet上下文,我的设置确实有效:' 。关键是我想让它们保留在应用程序上下文中。 – kotinuka

+0

我想你需要用DispatcherServlet配置的描述来更新你的文章。 –

+0

嗯......坦率地说,我将DispatherServlet添加到应用程序仅用于测试目的,以便查看如果将“组件扫描”移动到其上下文会发生什么情况。它实际上并不涉及我发布的问题,所以我可能不会在这里发布配置,以免混淆读者。 – kotinuka