Skip to content

Commit 00ca238

Browse files
committed
Merge branch '7.0.x'
# Conflicts: # framework-platform/framework-platform.gradle
2 parents facc7c5 + 2782a27 commit 00ca238

6 files changed

Lines changed: 75 additions & 11 deletions

File tree

framework-platform/framework-platform.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ javaPlatform {
99
dependencies {
1010
api(platform("com.fasterxml.jackson:jackson-bom:2.21.2"))
1111
api(platform("io.micrometer:micrometer-bom:1.16.5"))
12-
api(platform("io.netty:netty-bom:4.2.13.Final"))
12+
api(platform("io.netty:netty-bom:4.2.14.Final"))
1313
api(platform("io.projectreactor:reactor-bom:2025.0.5"))
1414
api(platform("io.rsocket:rsocket-bom:1.1.5"))
1515
api(platform("org.apache.groovy:groovy-bom:5.0.6"))
@@ -120,7 +120,7 @@ dependencies {
120120
api("org.glassfish:jakarta.el:4.0.2")
121121
api("org.graalvm.sdk:graal-sdk:22.3.1")
122122
api("org.hamcrest:hamcrest:3.0")
123-
api("org.hibernate.orm:hibernate-core:7.3.4.Final")
123+
api("org.hibernate.orm:hibernate-core:7.3.6.Final")
124124
api("org.hibernate.validator:hibernate-validator:9.1.0.Final")
125125
api("org.hsqldb:hsqldb:2.7.4")
126126
api("org.htmlunit:htmlunit:4.21.0")

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,12 +1154,19 @@ public void preInstantiateSingletons() throws BeansException {
11541154
if (mbd.isBackgroundInit()) {
11551155
Executor executor = getBootstrapExecutor();
11561156
if (executor != null) {
1157+
// Force initialization of depends-on beans in mainline thread.
11571158
String[] dependsOn = mbd.getDependsOn();
11581159
if (dependsOn != null) {
11591160
for (String dep : dependsOn) {
11601161
getBean(dep);
11611162
}
11621163
}
1164+
// Force initialization of factory reference in mainline thread.
1165+
String factoryBeanName = mbd.getFactoryBeanName();
1166+
if (factoryBeanName != null) {
1167+
getBean(factoryBeanName);
1168+
}
1169+
// Instantiate current bean in background thread.
11631170
CompletableFuture<?> future = CompletableFuture.runAsync(
11641171
() -> instantiateSingletonInBackgroundThread(beanName), executor);
11651172
addSingletonFactory(beanName, () -> {

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,11 @@ protected void processConfigurationClass(ConfigurationClass configClass, Predica
260260
return;
261261
}
262262
else if (configClass.isScanned()) {
263-
String beanName = configClass.getBeanName();
264-
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
265-
this.registry.removeBeanDefinition(beanName);
263+
if (existingClass.isImported()) {
264+
String beanName = configClass.getBeanName();
265+
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
266+
this.registry.removeBeanDefinition(beanName);
267+
}
266268
}
267269
// An implicitly scanned bean definition should not override an explicit import.
268270
return;

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,16 @@ void bootstrapWithCustomExecutorAndStrictLocking() {
197197
}
198198
}
199199

200+
@Test
201+
@Timeout(10)
202+
@EnabledForTestGroups(LONG_RUNNING)
203+
void bootstrapWithCustomExecutorAndLazyConfig() {
204+
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(CustomExecutorLazyBeanConfig.class);
205+
assertThat(ctx.getBeanFactory().containsSingleton("testBean1")).isTrue();
206+
assertThat(ctx.getBeanFactory().containsSingleton("testBean2")).isTrue();
207+
ctx.close();
208+
}
209+
200210

201211
@Configuration(proxyBeanMethods = false)
202212
static class UnmanagedThreadBeanConfig {
@@ -542,4 +552,36 @@ public TestBean testBean4(@Lazy TestBean testBean1, @Lazy TestBean testBean2, @L
542552
}
543553
}
544554

555+
556+
@Configuration(proxyBeanMethods = false)
557+
static class CustomExecutorLazyBeanConfig {
558+
559+
@Bean
560+
public ThreadPoolTaskExecutor bootstrapExecutor() {
561+
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
562+
executor.setThreadNamePrefix("Custom-");
563+
executor.setCorePoolSize(2);
564+
executor.initialize();
565+
return executor;
566+
}
567+
568+
@Configuration(proxyBeanMethods = false)
569+
@Lazy
570+
static class LazyBeanConfig {
571+
572+
@Bean(bootstrap = BACKGROUND)
573+
public TestBean testBean1() throws InterruptedException {
574+
Thread.sleep(6000);
575+
return new TestBean();
576+
}
577+
578+
@Bean(bootstrap = BACKGROUND)
579+
@Lazy
580+
public TestBean testBean2() throws InterruptedException {
581+
Thread.sleep(6000);
582+
return new TestBean();
583+
}
584+
}
585+
}
586+
545587
}

spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationIntegrationTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import example.scannable.CustomStereotype;
2727
import example.scannable.DefaultNamedComponent;
2828
import example.scannable.FooService;
29+
import example.scannable.FooServiceImpl;
2930
import example.scannable.MessageBean;
3031
import example.scannable.ScopedProxyTestBean;
3132
import example.scannable_implicitbasepackage.ComponentScanAnnotatedConfigWithImplicitBasePackage;
@@ -43,6 +44,7 @@
4344
import org.springframework.beans.factory.config.BeanDefinition;
4445
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
4546
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
47+
import org.springframework.beans.factory.support.RootBeanDefinition;
4648
import org.springframework.context.ApplicationContext;
4749
import org.springframework.context.EnvironmentAware;
4850
import org.springframework.context.ResourceLoaderAware;
@@ -84,6 +86,17 @@ void controlScan() {
8486
assertContextContainsBean(ctx, "fooServiceImpl");
8587
}
8688

89+
@Test
90+
void controlScanWithExplicitRegistration() {
91+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
92+
ctx.registerBeanDefinition("myFooService", new RootBeanDefinition(FooServiceImpl.class));
93+
ctx.scan(example.scannable.PackageMarker.class.getPackage().getName());
94+
ctx.refresh();
95+
96+
assertContextContainsBean(ctx, "myFooService");
97+
assertContextContainsBean(ctx, "fooServiceImpl");
98+
}
99+
87100
@Test
88101
void viaContextRegistration() {
89102
ApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanAnnotatedConfig.class);

spring-core/src/main/java/org/springframework/core/MethodParameter.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ public MethodParameter(Method method, int parameterIndex) {
117117
* return type; 0 for the first method parameter; 1 for the second method
118118
* parameter, etc.
119119
* @param nestingLevel the nesting level of the target type
120-
* (typically 1; for example, in case of a List of Lists, 1 would indicate the
121-
* nested List, whereas 2 would indicate the element of the nested List)
120+
* (1 for the top-level type; in case of a List of Lists, 2 would indicate
121+
* the nested List, whereas 3 would indicate the element of the nested List)
122122
*/
123123
public MethodParameter(Method method, int parameterIndex, int nestingLevel) {
124124
Assert.notNull(method, "Method must not be null");
@@ -142,8 +142,8 @@ public MethodParameter(Constructor<?> constructor, int parameterIndex) {
142142
* @param constructor the Constructor to specify a parameter for
143143
* @param parameterIndex the index of the parameter
144144
* @param nestingLevel the nesting level of the target type
145-
* (typically 1; for example, in case of a List of Lists, 1 would indicate the
146-
* nested List, whereas 2 would indicate the element of the nested List)
145+
* (1 for the top-level type; in case of a List of Lists, 2 would indicate
146+
* the nested List, whereas 3 would indicate the element of the nested List)
147147
*/
148148
public MethodParameter(Constructor<?> constructor, int parameterIndex, int nestingLevel) {
149149
Assert.notNull(constructor, "Constructor must not be null");
@@ -292,8 +292,8 @@ public void decreaseNestingLevel() {
292292

293293
/**
294294
* Return the nesting level of the target type
295-
* (typically 1; for example, in case of a List of Lists, 1 would indicate the
296-
* nested List, whereas 2 would indicate the element of the nested List).
295+
* (1 for the top-level type; in case of a List of Lists, 2 would indicate
296+
* the nested List, whereas 3 would indicate the element of the nested List).
297297
*/
298298
public int getNestingLevel() {
299299
return this.nestingLevel;

0 commit comments

Comments
 (0)