首先看一下异常:
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/