我在编写人员与用户管理模块代码时遇到一些问题,用户与人员是一对一关联,我想在personDao中持有UserDao,在UserDao中持有personDao,spring的配置如下(版本spring 2.0):

<bean id="personDao" class="cn.edu.ytu.oa.dao.impl.PersonDao4HibernateImpl" lazy-init="true">
    <property name="sessionFactory" ref="sessionFactory" />
    <property name="orgDao" ref="orgDao" />
    <property name="userDao" ref="userDao" />
</bean>
<bean id="userDao" class="cn.edu.ytu.oa.dao.impl.UserDao4HibernateImpl" lazy-init="true">
    <property name="sessionFactory" ref="sessionFactory" />
    <property name="personDao" ref="personDao" />
</bean>
<bean id="orgDao" class="cn.edu.ytu.oa.dao.impl.OrgDao4HibernateImpl">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>在做人员模块的单元测试的添加操作时,出现循环依赖的问题。
添加操做的代码:private static BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext-*.xml");

public void testAdd() {
PersonDao personDao = (PersonDao) beanFactory.getBean("personDao");

// Person person = new Person();
// person.setName("11111");
// personDao.addPerson(person, 1);
}异常信息如下:
java.lang.ExceptionInInitializerError
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.createTest(JUnit3TestLoader.java:78)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.getTest(JUnit3TestLoader.java:95)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.loadTests(JUnit3TestLoader.java:59)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:445)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personMgr' defined in file [D:\My document\eclipse\workspace\OA\oa_02\WebRoot\WEB-INF\classes\applicationContext-beans.xml]: Cannot resolve reference to bean 'personDao' while setting bean property 'personDao'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'personDao': Bean with name 'personDao' has been injected into other beans [userDao] in its raw version as part of a circular reference, but has eventually been wrapped (for example as part of auto-proxy creation). This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:254)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:128)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:955)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:729)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:416)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:245)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:141)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:242)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:156)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:290)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:348)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:92)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:77)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:68)
at cn.edu.ytu.oa.PersonDaoTest.<clinit>(PersonDaoTest.java:16)
... 11 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'personDao': Bean with name 'personDao' has been injected into other beans [userDao] in its raw version as part of a circular reference, but has eventually been wrapped (for example as part of auto-proxy creation). This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:423)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:245)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:141)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:242)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:156)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:246)
... 25 more
请高手帮忙解决一下!

解决方案 »

  1.   

    lz这个问题是个死锁,要想实例化personDao要先有UserDao,要想实例化UserDao先要有personDao.这个业务可以转化成一个中间类问题。建立一个新的compDao,持有personDao和UserDao的引用。
      

  2.   

    是不是用了AOP啊?要不然用setter注入不会报循环依赖错的吧
      

  3.   

    我的需求是这样的:由于一个用户对应一个人员,当人员删除时,那么对应用户也需要删除,所以在PersonDao中持有一个UserDao,
    当添加一个用户时,需要指定对应的人员标识,人员不存在不允许添加,所以在UserDao中持有一个PersonDao。
    请问在spring能否将我的需求改成如下形式:
    PersonDao personDao = new PersonDao();
    UserDao userDao = new UserDao();
    personDao.setUserDao(userDao);
    userDao.setPersonDao(personDao);添加一个Dao的话有点麻烦
      

  4.   

    添加一个Dao应该是相当与加入一个中间表吧,不是多对多的关系才需要这样吗?
      

  5.   

    当人员删除时,那么对应用户也需要删除
    当添加一个用户时,需要指定对应的人员标识,人员不存在不允许添加为什么非要在DAO层处理呢?
      

  6.   

    personDao中持有UserDao,在UserDao中持有personDao
    耦合度不就高了吗?
      

  7.   

    回复7楼你的意思在业务逻辑层来处理这些事情吗?我一直都不是很明白,到底哪些逻辑需要在Dao层来做,那些逻辑需要在业务逻辑层来做?还请高手指点指点!
      

  8.   

    个人认为DAO层只是对数据的,我比较习惯DAO里面只做单表的增删改查,业务层是处理删除人员以及删除人员附带的其他信息。就拿你的人员和用户为例,可以在业务层找出人员对应的用户,然后用用户的DAO删除不就可以了吗?
    如果用hibernate的话也可以在hibernate的映射文件里设置ondelete=cascade
      

  9.   


    如果是我的话,我会做成personDAO只操作person表,userDAO只操作user表
      

  10.   

    回复 11楼那么Dao层有什么对应的逻辑判断呢,比如在删除一个用户时,Dao层的接口一般是delUser(int userId),用hibenrate来做的话,需要先查询出
    user对象,判断user是否为空,再删除用户,那么像这种判断为空要不要放到Dao层来做呢?
      

  11.   

    你既然用hibernate了为什么不用ondelete=cascade?那么Dao层有什么对应的逻辑判断呢,比如在删除一个用户时,Dao层的接口一般是delUser(int userId),用hibenrate来做的话,需要先查询出 
    user对象,判断user是否为空,再删除用户,那么像这种判断为空要不要放到Dao层来做呢?
    判断是否为空不用放到DAO层吧,查出来user==null不就行了吗,只是删除的时候一个条件而已嘛
      

  12.   

    回复12楼:上面提到用户必须为员工分配,那么添加用户的接口不应该是addUser(User user, int personId)吗?这里不就必须要调用personDao的方法了吗?userDao怎么保证只操作user表
      

  13.   

    既然分层了为什么还要把“逻辑判断”放在DAO层呢?
      

  14.   

    上面提到用户必须为员工分配,那么添加用户的接口不应该是addUser(User user, int personId)吗?这里不就必须要调用personDao的方法了吗?userDao怎么保证只操作user表
    为什么要调用personDao的方法?addUser方法只要往user表里插一条数据就可以了,至于有没有这个员工在业务层判断,在业务层确定有这个员工了,才调用addUser(User user, int personId)不是吗?
      

  15.   

    如果那样的,Dao层不就一句话了?
    this.getHibernateTemplete().save(),
    this.getHibernateTemplete().update(),
    this.getHibernateTemplete().get(),
    this.getHibernateTemplete().delete()...
      

  16.   


    我建议让PersonDao单方面持有UserDao,因为这里有一个关联删除的逻辑,让Person引用User便于操作,
    而UserDao中持有一个PersonID我觉得就可以了。
      

  17.   

    personId不用持有吧,通过传参不就行了
      

  18.   

    既然分层了直接在业务层处理,不就避免了循环注入了吗,为什么要在Dao层处理呢
      

  19.   

    回复的一直询问楼主的DAO依赖问题,我也出现了这个问题,不过是业务逻辑相互引用,能不能先解决了提出的问题在给出相应的提议