Spring2.0中循环依赖如何解决

jxwnhj0717 2009-04-21 11:51:07
我在编写人员与用户管理模块代码时遇到一些问题,用户与人员是一对一关联,我想在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


请高手帮忙解决一下!
...全文
1268 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
wtuihpl 2010-12-25
  • 打赏
  • 举报
回复
回复的一直询问楼主的DAO依赖问题,我也出现了这个问题,不过是业务逻辑相互引用,能不能先解决了提出的问题在给出相应的提议。。。
cy_gogo 2009-04-22
  • 打赏
  • 举报
回复
既然分层了直接在业务层处理,不就避免了循环注入了吗,为什么要在Dao层处理呢
jxwnhj0717 2009-04-22
  • 打赏
  • 举报
回复
personId不用持有吧,通过传参不就行了
jxwnhj0717 2009-04-21
  • 打赏
  • 举报
回复
添加一个Dao应该是相当与加入一个中间表吧,不是多对多的关系才需要这样吗?
jxwnhj0717 2009-04-21
  • 打赏
  • 举报
回复
我的需求是这样的:由于一个用户对应一个人员,当人员删除时,那么对应用户也需要删除,所以在PersonDao中持有一个UserDao,
当添加一个用户时,需要指定对应的人员标识,人员不存在不允许添加,所以在UserDao中持有一个PersonDao。
请问在spring能否将我的需求改成如下形式:
PersonDao personDao = new PersonDao();
UserDao userDao = new UserDao();
personDao.setUserDao(userDao);
userDao.setPersonDao(personDao);

添加一个Dao的话有点麻烦
MT502 2009-04-21
  • 打赏
  • 举报
回复
是不是用了AOP啊?要不然用setter注入不会报循环依赖错的吧
jinxfei 2009-04-21
  • 打赏
  • 举报
回复
其实最好能够通过修改设计来避免循环依赖。
mumu_java 2009-04-21
  • 打赏
  • 举报
回复
lz这个问题是个死锁,要想实例化personDao要先有UserDao,要想实例化UserDao先要有personDao.这个业务可以转化成一个中间类问题。建立一个新的compDao,持有personDao和UserDao的引用。
jinxfei 2009-04-21
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 jxwnhj0717 的回复:]
我的需求是这样的:由于一个用户对应一个人员,当人员删除时,那么对应用户也需要删除,所以在PersonDao中持有一个UserDao,
当添加一个用户时,需要指定对应的人员标识,人员不存在不允许添加,所以在UserDao中持有一个PersonDao。
请问在spring能否将我的需求改成如下形式:
PersonDao personDao = new PersonDao();
UserDao userDao = new UserDao();
personDao.setUserDao(userDao);
userDao.setPersonDao(perso…
[/Quote]

我建议让PersonDao单方面持有UserDao,因为这里有一个关联删除的逻辑,让Person引用User便于操作,
而UserDao中持有一个PersonID我觉得就可以了。
lxy149434823 2009-04-21
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 jxwnhj0717 的回复:]
如果那样的,Dao层不就一句话了?
this.getHibernateTemplete().save(),
this.getHibernateTemplete().update(),
this.getHibernateTemplete().get(),
this.getHibernateTemplete().delete()...
[/Quote]

可以啊,如果你这四个方法写的够通用的话。这样代码复用率就最高了
jxwnhj0717 2009-04-21
  • 打赏
  • 举报
回复
如果那样的,Dao层不就一句话了?
this.getHibernateTemplete().save(),
this.getHibernateTemplete().update(),
this.getHibernateTemplete().get(),
this.getHibernateTemplete().delete()...
lxy149434823 2009-04-21
  • 打赏
  • 举报
回复
上面提到用户必须为员工分配,那么添加用户的接口不应该是addUser(User user, int personId)吗?这里不就必须要调用personDao的方法了吗?userDao怎么保证只操作user表


为什么要调用personDao的方法?addUser方法只要往user表里插一条数据就可以了,至于有没有这个员工在业务层判断,在业务层确定有这个员工了,才调用addUser(User user, int personId)不是吗?
lxy149434823 2009-04-21
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 jxwnhj0717 的回复:]
回复 11楼

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


既然分层了为什么还要把“逻辑判断”放在DAO层呢?
jxwnhj0717 2009-04-21
  • 打赏
  • 举报
回复
回复12楼:

上面提到用户必须为员工分配,那么添加用户的接口不应该是addUser(User user, int personId)吗?这里不就必须要调用personDao的方法了吗?userDao怎么保证只操作user表
lxy149434823 2009-04-21
  • 打赏
  • 举报
回复
你既然用hibernate了为什么不用ondelete=cascade?



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


判断是否为空不用放到DAO层吧,查出来user==null不就行了吗,只是删除的时候一个条件而已嘛

jxwnhj0717 2009-04-21
  • 打赏
  • 举报
回复
回复 11楼

那么Dao层有什么对应的逻辑判断呢,比如在删除一个用户时,Dao层的接口一般是delUser(int userId),用hibenrate来做的话,需要先查询出
user对象,判断user是否为空,再删除用户,那么像这种判断为空要不要放到Dao层来做呢?
lxy149434823 2009-04-21
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 jxwnhj0717 的回复:]
回复8楼

人员和用户是一对一的关系,只有员工才能拥有有切只有一个账户,不是员工无法获取账户,这两者耦合没有什么问题吧
如果换做您来设计的话,请问你会怎样降低两者的耦合度呢?
[/Quote]

如果是我的话,我会做成personDAO只操作person表,userDAO只操作user表
lxy149434823 2009-04-21
  • 打赏
  • 举报
回复
个人认为DAO层只是对数据的,我比较习惯DAO里面只做单表的增删改查,业务层是处理删除人员以及删除人员附带的其他信息。就拿你的人员和用户为例,可以在业务层找出人员对应的用户,然后用用户的DAO删除不就可以了吗?


如果用hibernate的话也可以在hibernate的映射文件里设置ondelete=cascade
jxwnhj0717 2009-04-21
  • 打赏
  • 举报
回复
回复8楼

人员和用户是一对一的关系,只有员工才能拥有有切只有一个账户,不是员工无法获取账户,这两者耦合没有什么问题吧
如果换做您来设计的话,请问你会怎样降低两者的耦合度呢?
jxwnhj0717 2009-04-21
  • 打赏
  • 举报
回复
回复7楼

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

67,512

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧