No qualifying bean of type [javax.persistence.EntityManage] 异常问题的解决

来源:互联网 发布:和平典范 知乎 编辑:程序博客网 时间:2024/04/28 20:32

引言: 在Spring Web项目中一般都会使用OpenEntityManagerInViewFilter来保证JPA session的正常关闭,在笔者的项目中,使用了Spring + Spring Data + JPA + Hibernate来的架构来组织项目,碰到了org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' is defined 的异常信息,将过一番查找之后,方才发现问题是加载顺序的问题....

1. 项目背景介绍

   项目中使用的技术有: Spring+Spring Data, JPA, Hibernate等来贯穿项目的主题架构。

2.  Session异常关闭的处理机制

   在Java Web项目中使用Hibernate经常会遇到LazyInitializationException 。这是因为controller和model层(java代码)将通过JPA的一些启用了延迟加载功能 的领域(如用getRefrence() 方法或者在关联关系中采用fetch=FetchType.LAZY )返回给view层(jsp代码)的时候,由于加载领域对象的JPA Session已经关闭,导致这些延迟加载的数据访问异常。

这时就可以使用OpenEntityManagerInViewFilter来将一个JPAsession与一次完整的请求过程对应的线程相绑定。

   解决办法:

<filter>          <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>          <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>          <init-param>          <!-- 指定org.springframework.orm.jpa.LocalEntityManagerFactoryBean在spring配置文件中的名称,默认值为entityManagerFactory          如果LocalEntityManagerFactoryBean在spring中的名称不是entityManagerFactory,该参数一定要指定,否则会出现找不到entityManagerFactory的例外 -->              <param-name>entityManagerFactoryBeanName</param-name>              <param-value>entityManagerFactory</param-value>          </init-param>       </filter>      <filter-mapping>          <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>          <url-pattern>/*</url-pattern>      </filter-mapping>  
3. 异常问题的出现

   在解决了Session异常关闭之后,在启动服务器的时候,就出现了如下异常信息:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' is definedat org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:575)at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1111)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1121)at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.lookupEntityManagerFactory(OpenEntityManagerInViewFilter.java:222)at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.lookupEntityManagerFactory(OpenEntityManagerInViewFilter.java:205)at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:150)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313)at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)at java.lang.Thread.run(Thread.java:662)
从异常信息的分析可知道,OpenEntityManagerInViewFilter中对entityManagerFactory有依赖,需要对其在Spring中声明的实例依赖。 但是没有找到合适的实例。

  可是entityManagerFactory的确已经声明在了spring的配置文件之中了。问题在哪里呢?

4. 问题分析以及定位

   项目中entityManagerFactory在Spring中的配置文件定义的,经过检查,工作正常,不存在问题。

<beans:bean id="entityManagerFactory"class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><beans:property name="dataSource" ref="dataSource" />       <!--         <beans:property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>         --><beans:property name="jpaVendorAdapter"><beans:beanclass="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"><!-- hibernate properties definition --></beans:bean></beans:property><beans:property name="persistenceUnitName" value="myPersistenceUnit" /><beans:property name="packagesToScan"><beans:list><beans:value>com.creditease.bsettle.pay.model</beans:value></beans:list></beans:property><beans:property name="loadTimeWeaver"><beans:beanclass="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" /></beans:property><beans:property name="jpaPropertyMap"><beans:map><beans:entry key="showSql" value="true"></beans:entry><beans:entry key="generateDdl" value="false"></beans:entry><beans:entry key="hibernate.format_sql" value="true"></beans:entry><beans:entry key="hibernate.dialect"value="org.hibernate.dialect.Oracle10gDialect"></beans:entry></beans:map></beans:property></beans:bean>
  于是把问题的怀疑点聚焦在web.xml初始化文件上,是否其中存在什么问题呢?

  在web.xml中存在2个地方进行spring实例的初始化操作:

    <context-param><param-name>contextConfigLocation</param-name><param-value>classpath:META-INF/spring-config.xml</param-value></context-param>
  第二个位置是:

<servlet><servlet-name>appServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:META-INF/applicationContext.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet>
 存在错误异常的加载顺序中,entityManagerFactory是在第二个位置中进行加载的。但是OpenEntityManagerInViewFilter是否加载的顺序在其之前,然后就造成了这样的问题呢?

 经过试验,果然是加载顺序的问题,将数据库加载的顺序提前即可。

5. 总结

  基于上面的问题,我们可以看到, OpenEntityManagerInViewFilter是在系统启动过程中,优先被加载的,同时其对entityManagerFactory有依赖,就要求同时可以初始化entityManagerFactory的实例。

   通过调整初始化的顺序,即可很好的修正上述的问题。


参考资料:

1. http://whoosh.iteye.com/blog/1300721


0 1
原创粉丝点击