Browse Source

Introduce spring.locking.strict=true flag for 6.1.x style bean creation locking

Closes gh-34303
pull/34656/head
Juergen Hoeller 9 months ago
parent
commit
6905dff660
  1. 15
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  2. 41
      spring-context/src/test/java/org/springframework/context/annotation/BackgroundBootstrapTests.java
  3. 1
      spring-core/src/main/java/org/springframework/core/SpringProperties.java

15
spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

@ -76,6 +76,7 @@ import org.springframework.core.NamedThreadLocal; @@ -76,6 +76,7 @@ import org.springframework.core.NamedThreadLocal;
import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.SpringProperties;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
@ -128,6 +129,17 @@ import org.springframework.util.StringUtils; @@ -128,6 +129,17 @@ import org.springframework.util.StringUtils;
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/**
* System property that instructs Spring to enforce string locking during bean creation,
* rather than the mix of strict and lenient locking that 6.2 applies by default. Setting
* this flag to "true" restores 6.1.x style locking in the entire pre-instantiation phase.
* @since 6.2.6
* @see #preInstantiateSingletons()
*/
public static final String STRICT_LOCKING_PROPERTY_NAME = "spring.locking.strict";
private static final boolean lenientLockingAllowed = !SpringProperties.getFlag(STRICT_LOCKING_PROPERTY_NAME);
@Nullable
private static Class<?> jakartaInjectProviderClass;
@ -1031,7 +1043,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1031,7 +1043,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
@Nullable
protected Boolean isCurrentThreadAllowedToHoldSingletonLock() {
return (this.preInstantiationPhase ? this.preInstantiationThread.get() != PreInstantiation.BACKGROUND : null);
return (lenientLockingAllowed && this.preInstantiationPhase ?
this.preInstantiationThread.get() != PreInstantiation.BACKGROUND : null);
}
@Override

41
spring-context/src/test/java/org/springframework/context/annotation/BackgroundBootstrapTests.java

@ -20,11 +20,15 @@ import org.junit.jupiter.api.Test; @@ -20,11 +20,15 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.SpringProperties;
import org.springframework.core.testfixture.EnabledForTestGroups;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.context.annotation.Bean.Bootstrap.BACKGROUND;
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
@ -56,6 +60,21 @@ class BackgroundBootstrapTests { @@ -56,6 +60,21 @@ class BackgroundBootstrapTests {
ctx.close();
}
@Test
@Timeout(5)
@EnabledForTestGroups(LONG_RUNNING)
void bootstrapWithStrictLockingThread() {
SpringProperties.setFlag(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME);
try {
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(StrictLockingBeanConfig.class);
assertThat(ctx.getBean("testBean2", TestBean.class).getSpouse()).isSameAs(ctx.getBean("testBean1"));
ctx.close();
}
finally {
SpringProperties.setProperty(DefaultListableBeanFactory.STRICT_LOCKING_PROPERTY_NAME, null);
}
}
@Test
@Timeout(5)
@EnabledForTestGroups(LONG_RUNNING)
@ -148,6 +167,28 @@ class BackgroundBootstrapTests { @@ -148,6 +167,28 @@ class BackgroundBootstrapTests {
}
@Configuration(proxyBeanMethods = false)
static class StrictLockingBeanConfig {
@Bean
public TestBean testBean1(ObjectProvider<TestBean> testBean2) {
new Thread(testBean2::getObject).start();
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
return new TestBean();
}
@Bean
public TestBean testBean2(ConfigurableListableBeanFactory beanFactory) {
return new TestBean((TestBean) beanFactory.getSingleton("testBean1"));
}
}
@Configuration(proxyBeanMethods = false)
static class CircularReferenceBeanConfig {

1
spring-core/src/main/java/org/springframework/core/SpringProperties.java

@ -39,6 +39,7 @@ import org.springframework.lang.Nullable; @@ -39,6 +39,7 @@ import org.springframework.lang.Nullable;
* @author Juergen Hoeller
* @since 3.2.7
* @see org.springframework.beans.StandardBeanInfoFactory#IGNORE_BEANINFO_PROPERTY_NAME
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory#STRICT_LOCKING_PROPERTY_NAME
* @see org.springframework.core.env.AbstractEnvironment#IGNORE_GETENV_PROPERTY_NAME
* @see org.springframework.expression.spel.SpelParserConfiguration#SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME
* @see org.springframework.jdbc.core.StatementCreatorUtils#IGNORE_GETPARAMETERTYPE_PROPERTY_NAME

Loading…
Cancel
Save