使用`sessionFactory`和`transactionManager`解决Spring中的循环依赖问题

时间:2013-05-31 22:44:22

标签: java spring hibernate

我正在使用 Hibernate 3.6 Spring 3.2

当我启动应用程序时,我似乎有一个循环依赖。

我的applicationContext.xml(简化)看起来像这样:

<beans
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

  <bean id="wicketApplication"
        class="us.ak.state.revenue.cssd.Personnel.QuickStartApplication" />
  <bean id="sessionFactory"
        class="us.ak.state.revenue.cssd.Personnel.utils.SessionFactoryBean" >
    <property name="configLocation" value="classpath:hibernate.cfg.xml">
    </property>
    <property name="entityInterceptor">
      <ref bean="interceptor" />
    </property>
  </bean>

  <!-- using Annotations -->
  <tx:annotation-driven transaction-manager="txManager" />

  <!-- setup transaction manager  -->
  <bean id="txManager"
      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <!--
    <property name="sessionFactory">
      <ref bean="sessionFactory" />
    </property>
    -->
  </bean>

  <bean id="transactionTemplate"
        class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="txManager"/>
  </bean>

  <!-- List functions that should be Transactional -->
  <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="find*"     propagation="REQUIRED"/>
      <tx:method name="size*"     propagation="REQUIRED"/>
      <tx:method name="attach*"   propagation="REQUIRED"/>
      <tx:method name="save"      propagation="REQUIRED"/>
      <tx:method name="persist"   propagation="REQUIRED"/>
      <tx:method name="update"    propagation="REQUIRED"/>
      <tx:method name="merge"     propagation="REQUIRED"/>
      <tx:method name="delete"    propagation="REQUIRED"/>
      <tx:method name="onAttach*" propagation="REQUIRED"/>
      <tx:method name="onSave"    propagation="REQUIRED"/>
      <tx:method name="onPersist" propagation="REQUIRED"/>
      <tx:method name="onUpdate"  propagation="REQUIRED"/>
      <tx:method name="onMerge"   propagation="REQUIRED"/>
      <tx:method name="onDelete"  propagation="REQUIRED"/>          
    </tx:attributes>
  </tx:advice>

  <!-- TODO: look into creating a custom interceptor later -->
  <bean id="interceptor" class="org.hibernate.EmptyInterceptor"></bean>

  <bean id="AuditDAO" class="us.ak.state.revenue.cssd.dao.AuditDAO" >
    <property name="sessionFactory" ref="sessionFactory"/>
  </bean>
  <!-- other DAOs omitted for brevity -->

  <context:component-scan base-package="us.ak.state.revenue.cssd" >
    <context:include-filter type="assignable"
            expression="us.ak.state.revenue.cssd.Personnel.dao.BaseHibernateDAO" />
  </context:component-scan>
</beans>

当我尝试运行我的应用程序时,我的错误日志中会出现以下内容:

java.lang.IllegalStateException: Failed to load ApplicationContext
  at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
  at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:122) 
  at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:105) 
  at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:74)
  at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:312)
  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211) 
  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288) 
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
  at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
  at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
  at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
  at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
  at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
  at org.junit.runners.Suite.runChild(Suite.java:115)
  at org.junit.runners.Suite.runChild(Suite.java:23)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
  at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
  at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
  at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
  at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
  at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77) 
  at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
  at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
  Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: 
    Error creating bean with name 'wicketApplication' defined in class path resource [testApplicationContext.xml]: 
      Unsatisfied dependency expressed through bean property 'iAuditDAO': : 
        Error creating bean with name 'AuditDAO' defined in class path resource [testApplicationContext.xml]: 
          Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
    Error creating bean with name 'sessionFactory' defined in class path resource [testApplicationContext.xml]: 
      Unsatisfied dependency expressed through bean property 'eventListeners': : 
        Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
          Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory';
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
    Error creating bean with name 'sessionFactory': 
      FactoryBean which is currently in creation returned null from getObject; 
  nested exception is org.springframework.beans.factory.BeanCreationException: 
    Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
      Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
    Error creating bean with name 'sessionFactory': FactoryBean which is currently in creation returned null from getObject; 
  nested exception is org.springframework.beans.factory.BeanCreationException: 
    Error creating bean with name 'AuditDAO' defined in class path resource [testApplicationContext.xml]: 
      Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
    nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
    Error creating bean with name 'sessionFactory' defined in class path resource [testApplicationContext.xml]: 
  Unsatisfied dependency expressed through bean property 'eventListeners': : 
    Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
    Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
    Error creating bean with name 'sessionFactory': 
      FactoryBean which is currently in creation returned null from getObject; nested exception is org.springframework.beans.factory.BeanCreationException: 
        Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
          Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
    Error creating bean with name 'sessionFactory': 
      FactoryBean which is currently in creation returned null from getObject
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1215)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1107)
  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)
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
  at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
  at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
  at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:120)
  at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
  at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100) 
  at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
  at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
  at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
  ... 36 more Caused by: org.springframework.beans.factory.BeanCreationException:
   Error creating bean with name 'AuditDAO' defined in class path resource [testApplicationContext.xml]: 
    Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
    Error creating bean with name 'sessionFactory' defined in class path resource [testApplicationContext.xml]: 
      Unsatisfied dependency expressed through bean property 'eventListeners': : 
       Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
         Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
    Error creating bean with name 'sessionFactory': 
      FactoryBean which is currently in creation returned null from getObject; 
  nested exception is org.springframework.beans.factory.BeanCreationException: 
    Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
      Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
    Error creating bean with name 'sessionFactory': 
      FactoryBean which is currently in creation returned null from getObject
  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)
  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1393)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1134)
  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)
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:910)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:853)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1200)  
  ... 52 more Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: 
    Error creating bean with name 'sessionFactory' defined in class path resource [testApplicationContext.xml]: 
    Unsatisfied dependency expressed through bean property 'eventListeners': : 
      Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
        Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
  Error creating bean with name 'sessionFactory': 
    FactoryBean which is currently in creation returned null from getObject; nested exception is org.springframework.beans.factory.BeanCreationException: 
      Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
        Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
    Error creating bean with name 'sessionFactory': 
      FactoryBean which is currently in creation returned null from getObject
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1215)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1107)
  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)
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323)
  ... 65 more Caused by: org.springframework.beans.factory.BeanCreationException:
    Error creating bean with name 'txManager' defined in class path resource [testApplicationContext.xml]: 
      Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; 
  nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
    Error creating bean with name 'sessionFactory': 
      FactoryBean which is currently in creation returned null from getObject
  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)
  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1393)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1134)
  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)
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:910)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:840)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768) 
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1200)  
  ... 73 more Caused by: 
    org.springframework.beans.factory.BeanCurrentlyInCreationException: 
      Error creating bean with name 'sessionFactory': 
        FactoryBean which is currently in creation returned null from getObject
  at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:156)
  at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:109)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1448)
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:249)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323)
  ... 86 more

那么如何更正我的applicationContext.xml以更正错误?

更新
根据@kaviddiss的建议,我正在添加有关SessionFactoryBean的详细信息 public class SessionFactoryBean extends LocalSessionFactoryBean它所做的就是 @Override newConfiguration()检查服务器运行情况并设置数据库连接字符串和日志级别(调试与信息)。

我以为我已经从<beans ...>中进行了自动装配我是否需要明确将其设置为关/禁用?

2 个答案:

答案 0 :(得分:1)

除了xml配置,您还配置了自动装配,这两个可能会创建循环依赖。堆栈指的是可能导致问题的bean属性eventListener。您可能希望在us.ak.state.revenue.cssd.Personnel.utils.SessionFactoryBean类中包含更多详细信息以获取更多帮助。您还可以尝试注释掉XML配置的某些部分和/或一些自动装配注释,直到您弄清楚如何打破循环依赖。

答案 1 :(得分:1)

从XML中删除Hibernate实体拦截器配置。它可能被TX AOP拾取,从而导致循环依赖(通过txManager)。

稍后当你创建自己的拦截器时,不要忘记添加AopInfrastructureBean接口,这样它就不会成为AOP包装的主题。


UPDATE 我刚刚意识到XML中没有切入点定义,并且正在使用<tx:annotation-driven>(即AOP基于@Transactional注释)。这意味着我的回答不正确。