diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java index 8b0f4c68cb0..80823e01a01 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java @@ -132,53 +132,48 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg try { // A SmartFactoryBean may return multiple object types -> do not cache. boolean smart = (factory instanceof SmartFactoryBean); - Object object = (!smart ? this.factoryBeanObjectCache.get(beanName) : null); - if (object == null) { - if (locked) { - // The common case: within general singleton lock. + // Defensively synchronize against non-thread-safe FactoryBean.getObject() implementations, + // potentially to be called from a background thread while the main thread currently calls + // the same getObject() method within the singleton lock. + synchronized (factory) { + Object object = (!smart ? this.factoryBeanObjectCache.get(beanName) : null); + if (object == null) { object = doGetObjectFromFactoryBean(factory, requiredType, beanName); - } - else { - // Fall back to local synchronization on the given FactoryBean instance, - // as a defensive measure for non-thread-safe FactoryBean implementations. - synchronized (factory) { - object = doGetObjectFromFactoryBean(factory, requiredType, beanName); + // Only post-process and store if not put there already during getObject() call above + // (for example, because of circular reference processing triggered by custom getBean calls) + Object alreadyThere = (!smart ? this.factoryBeanObjectCache.get(beanName) : null); + if (alreadyThere != null) { + object = alreadyThere; } - } - // Only post-process and store if not put there already during getObject() call above - // (for example, because of circular reference processing triggered by custom getBean calls) - Object alreadyThere = (!smart ? this.factoryBeanObjectCache.get(beanName) : null); - if (alreadyThere != null) { - object = alreadyThere; - } - else { - if (shouldPostProcess) { - if (locked) { - if (isSingletonCurrentlyInCreation(beanName)) { - // Temporarily return non-post-processed object, not storing it yet - return object; - } - beforeSingletonCreation(beanName); - } - try { - object = postProcessObjectFromFactoryBean(object, beanName); - } - catch (Throwable ex) { - throw new BeanCreationException(beanName, - "Post-processing of FactoryBean's singleton object failed", ex); - } - finally { + else { + if (shouldPostProcess) { if (locked) { - afterSingletonCreation(beanName); + if (isSingletonCurrentlyInCreation(beanName)) { + // Temporarily return non-post-processed object, not storing it yet + return object; + } + beforeSingletonCreation(beanName); + } + try { + object = postProcessObjectFromFactoryBean(object, beanName); + } + catch (Throwable ex) { + throw new BeanCreationException(beanName, + "Post-processing of FactoryBean's singleton object failed", ex); + } + finally { + if (locked) { + afterSingletonCreation(beanName); + } } } - } - if (!smart && containsSingleton(beanName)) { - this.factoryBeanObjectCache.put(beanName, object); + if (!smart && containsSingleton(beanName)) { + this.factoryBeanObjectCache.put(beanName, object); + } } } + return object; } - return object; } finally { if (locked) {