`
phpxiaoxin
  • 浏览: 252995 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

spring 循环依赖引出的问题

阅读更多

首先看一下异常:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'elementServiceFactory': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:297)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:216)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:671)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:610)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1076)
	... 97 more

 

看了对象的关联关系,的确存在这个问题,最终问题解决也很简单:

网上有一种说法是在bean上加lazy-init="true"

    <bean name="elementServiceFactory" class="gov.sdta.dtss.service.info.ElementServiceFactory" lazy-init="true">

 参照:http://blog.csdn.net/cooper_lyt/archive/2008/11/25/3367684.aspx

但是我试了,这个方式对我不起作用。

 

于是我找到了另外的方式,使用set方式注入(原来是构造注入的):

参照:http://hi.baidu.com/dongbeiman/blog/item/95b39111649a5777ca80c4b1.html

然后问题就ok了。

 

下面说下我的问题的现象:

 

相同的代码不同的机器运行,同样的环境,一个报上述错误,一个正常启动。没办法,只好debug了,搞好spring 2.5.6的代码,首先找到了报错的大体位置“DefaultSingletonBeanRegistry”,相关代码如下:

 

private final Set singletonsCurrentlyInCreation = Collections.synchronizedSet(new HashSet());

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
		Assert.notNull(beanName, "'beanName' must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while the singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet();
				}
				try {
					singletonObject = singletonFactory.getObject();
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Iterator it = this.suppressedExceptions.iterator(); it.hasNext();) {
							ex.addRelatedCause((Exception) it.next());
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				addSingleton(beanName, singletonObject);
			}
			return (singletonObject != NULL_OBJECT ? singletonObject : null);
		}
	}


protected void beforeSingletonCreation(String beanName) {
		if (!this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
 

singletonsCurrentlyInCreation 是一个set,当出现循环依赖的时候就会出现相同name的bean被同时add两次,而失败,抛出BeanCurrentlyInCreationException的异常。这个是很正常的。但是为设么另外一台机器没这个问题呢?

 

debug加上condition断下来发现,相同的beanName,是由不同的类引用的,这个是正常的,但是我的第一次断下来是有循环依赖的引用的,而他的则是另外一个类,这个类与出问题的类并没有循环依赖的问题,于是他的没有报错,而我的则报错了。

 

这说明一个问题,spring初始化的时候bean的初始化顺序是没先后顺序的,这个以前也听说过,那么怎么能调整先后顺序呢?找了一些资料(http://guoliangqi.iteye.com/blog/632697),加了initmethod,没有效果,于是放弃了,但是我想知道我的顺序是什么样子,于是再下断点,在DefaultListableBeanFactory中找到了如下代码:

 

public void preInstantiateSingletons() throws BeansException {
		if (this.logger.isInfoEnabled()) {
			this.logger.info("Pre-instantiating singletons in " + this);
		}

		synchronized (this.beanDefinitionMap) {
			for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
				String beanName = (String) it.next();
				RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
				if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
					if (isFactoryBean(beanName)) {
						FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
						if (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()) {
							getBean(beanName);
						}
					}
					else {
						getBean(beanName);
					}
				}
			}
		}
	}
 

 

在:resolvableDependencies.keySet()中,我拿到了list中的所有内容,大概有800多个,而且前4个还是spring的bean(org.springframework.context.annotation.internalPersistenceAnnotationProcessor)

 

比对了我的list与正常启动机器的list,的确两个bean的顺序一个在前一个在后,那这个时候问题的现象就好解释了。

相同的代码,不同机器的map的hash是不一样的,因此导致keyset之后,拿到的list排序也不一样,所以他的能起来。

 

因为他的类引用了有循环依赖问题的类,并将之正确常见出来,而我则在床两两个循环依赖的类的时候互相创建,导致创建失败。(注:不知道真实远离,我是这么理解的,知道原理的情指正,谢谢。)

 

所以,这个看起来非常诡异的问题,就这样搞定了。折腾了一天才搞定,不过还好,有不少进步。

 

最后提醒大家,碰到问题,不要说人品问题,一定要找出“人品问题”到底是哪里的问题,以便把这个人品值加上去 :)

 

这篇文章可以参考: http://www.goldendoc.org/2010/11/spring-ioc%E4%B9%8Bbeanfactory/

 

分享到:
评论

相关推荐

    Spring源码最难问题:当Spring AOP遇上循环依赖.docx

    Spring源码最难问题:当Spring AOP遇上循环依赖 Spring源码中最难的问题之一是循环依赖问题,当Spring AOP遇上循环依赖时,该如何解决? Spring通过三级缓存机制解决循环依赖的问题。 在Spring中,bean的实例化...

    Spring循环依赖案例问题详解.docx

    然而,Spring通过其强大的依赖注入机制,能够处理大部分场景下的循环依赖问题,但并非所有情况都能解决。 首先,让我们看看Spring如何处理单例bean(Singleton Beans)的循环依赖。在默认情况下,Spring采用三级...

    Spring循环依赖debug源码图

    Spring循环依赖debug源码图

    理解Spring循环依赖.docx

    Spring的循环依赖处理机制是其依赖注入的核心功能之一,它使得开发者能够编写松耦合的代码,而无需过多关注依赖关系可能导致的问题。然而,了解其限制并合理设计bean之间的依赖关系,是避免潜在问题的关键。在编程时...

    Springbean循环依赖问题,与解决方案。.docx

    SpringBean 循环依赖问题与解决方案 SpringBean 循环依赖问题是指在 Spring 框架中,多个 Bean 之间存在相互依赖关系,导致 Bean 创建失败或无法正确注入的问题。这种问题常见于大型项目中,特别是在复杂的业务系统...

    Spring5.0源码深度解析之SpringBean循环依赖问题解决方案.docx

    Spring5.0源码深度解析之SpringBean循环依赖问题解决方案 Spring5.0源码深度解析之SpringBean循环依赖问题解决方案是指在Spring框架中如何解决Bean的循环依赖问题。在Spring框架中,Bean的循环依赖指的是两个或多个...

    Spring循环依赖.vsdx

    Spring循环依赖.vsdx

    Spring 解决循环依赖的 3 种方式.docx

    但如果开发者明确指定允许循环依赖,Spring会在每次请求prototype Bean时进行实例化和依赖注入,这可能导致每次请求都会创建一个新的Bean实例,从而避免了循环引用的问题。 总结来说,Spring通过“三级缓存”和“半...

    spring bean循环依赖时序图

    spring bean循环依赖时序图详细的描述了spring的循环依赖关系,帮我们快速了解spring是如何优雅的进行处理的

    简单了解Spring循环依赖解决过程

    Spring 框架中循环依赖是一个常见的问题,它指的是两个或多个 Bean 之间存在的相互依赖关系,例如 A 依赖 B,B 依赖 A,这种情况下,Spring 需要解决这个循环依赖关系,以便正确地实例化和初始化 Bean。 在 Spring ...

    spring多个动态代理导致循环依赖报错问题解决

    了解并熟练掌握以上策略,可以帮助我们更有效地应对Spring中的动态代理导致的循环依赖问题。 为了更好地理解并实践这些解决方案,你可以参考提供的压缩包文件`demo-spring`中的示例代码,通过实际操作来加深印象。...

    Spring循环依赖的解决办法,你真的懂了吗

    Spring循环依赖的解决办法 Spring框架中,循环依赖是指两个或多个Bean相互引用,形成一个环。这篇文章主要介绍了Spring循环依赖的解决办法。在Spring中,循环依赖可以分为两种场景:构造器的循环依赖和属性的循环...

    3. 循环依赖问题(三级缓存).xmind

    《spring源码之循环依赖和三级缓存》整理,本人水平有限,从网上找的资料整合之后做的,请辩证的看待其中内容。

    Spring三级缓存解决循环依赖.pdf

    Spring三级缓存解决循环依赖.pdf

    Spring如何解决循环依赖的问题

    Spring框架在处理依赖注入时,会遇到一个棘手的问题,那就是循环依赖。循环依赖是指两个或多个bean之间形成一个依赖闭环,导致它们无法被正常初始化。本文将详细讲解Spring如何解决这一问题,以及为何它仅支持单例...

    spring循环依赖策略解析

    在Spring中,循环依赖只有当两个条件满足的情况下是没问题的:1.Bean是单例,2.通过属性注入的情况。否则,如果是通过构造器依赖,或者不是单例模式的情况下循环依赖就会抛出异常BeanCurrentlyInCreationException。...

    基于SpringBoot构造器注入循环依赖及解决方式

    在Spring Boot应用中,构造器注入是一种常见的依赖注入方式,但它可能会引发循环依赖的问题。循环依赖是指两个或多个Bean之间形成一个闭环,彼此依赖对方,导致Spring容器在初始化Bean时无法确定创建顺序,从而抛出...

    Spring使用时的循环依赖问题详解.docx

    Spring通过其强大的依赖注入机制,大部分情况下能够自动解决单例bean之间的循环依赖问题,但并非对所有类型的循环依赖都有效。 首先,我们来看一个简单的例子: ```java @Configuration @ComponentScan public ...

    使用MyEclipse查看Spring的依赖视图

    ### 使用MyEclipse查看Spring的依赖视图 #### 一、引言 随着软件开发的复杂度不断提高,项目之间的依赖关系变得越来越复杂。在这种背景下,有效地管理这些依赖关系成为了一个非常重要的任务。Spring框架作为Java...

    Spring循环依赖的三种方式(推荐)

    Spring 循环依赖的三种方式 Spring 循环依赖是指在 ...Spring 提供了多种方式来解决循环依赖问题,包括构造器参数循环依赖、setter 方法循环依赖和使用 @Autowired 注解。开发者可以根据实际情况选择合适的解决方案。

Global site tag (gtag.js) - Google Analytics