From 467d5f3ca3af5c9ed2926260553484d99ddb8f79 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 13 Jan 2025 17:48:13 +0100 Subject: [PATCH] Try late locking for waiting on specific bean to be finished Closes gh-34186 --- .../support/DefaultSingletonBeanRegistry.java | 22 +++++++++++++++++-- .../factory/BeanFactoryLockingTests.java | 6 +---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java index bebcc115400..07c33922a07 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -279,7 +279,25 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } - beforeSingletonCreation(beanName); + + try { + beforeSingletonCreation(beanName); + } + catch (BeanCurrentlyInCreationException ex) { + if (locked) { + throw ex; + } + // Try late locking for waiting on specific bean to be finished. + this.singletonLock.lock(); + locked = true; + // Singleton object should have appeared in the meantime. + singletonObject = this.singletonObjects.get(beanName); + if (singletonObject != null) { + return singletonObject; + } + beforeSingletonCreation(beanName); + } + boolean newSingleton = false; boolean recordSuppressedExceptions = (locked && this.suppressedExceptions == null); if (recordSuppressedExceptions) { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryLockingTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryLockingTests.java index d7c3291d5d5..fbff4b0e746 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryLockingTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryLockingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.testfixture.beans.TestBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * @author Juergen Hoeller @@ -56,9 +55,6 @@ class BeanFactoryLockingTests { @Override public void afterPropertiesSet() throws Exception { Thread thread = new Thread(() -> { - // Fail for circular reference from other thread - assertThatExceptionOfType(BeanCurrentlyInCreationException.class).isThrownBy(() -> - beanFactory.getBean(ThreadDuringInitialization.class)); // Leniently create unrelated other bean outside of singleton lock assertThat(beanFactory.getBean(TestBean.class).getName()).isEqualTo("tb"); // Creation attempt in other thread was successful