Skip to content

Commit cafb5cf

Browse files
snicolljhoeller
andcommitted
Refine preDetermineBeanTypes algorithm
This commit refines the preDetermineBeanTypes algorithm that AOT uses to approximate the order of preInstantiateSingletons more closely. Previously, the algorithm assumed that all beans where non-lazy singletons in terms of initialization order, which led to inconsistent order in CGLIB proxy generation. We now explicitly park lazy beans so that their types are determined during a second phase, matching the order of regular initialization order. Closes gh-32701 Co-authored-by: Juergen Hoeller <[email protected]>
1 parent 9d2c6f8 commit cafb5cf

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

Diff for: spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java

+32-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.lang.reflect.Constructor;
21+
import java.util.ArrayList;
2122
import java.util.List;
2223
import java.util.concurrent.atomic.AtomicBoolean;
2324
import java.util.function.Supplier;
@@ -423,16 +424,37 @@ private void preDetermineBeanTypes(RuntimeHints runtimeHints) {
423424
PostProcessorRegistrationDelegate.loadBeanPostProcessors(
424425
this.beanFactory, SmartInstantiationAwareBeanPostProcessor.class);
425426

427+
List<String> lazyBeans = new ArrayList<>();
428+
429+
// First round: non-lazy singleton beans in definition order,
430+
// matching preInstantiateSingletons.
426431
for (String beanName : this.beanFactory.getBeanDefinitionNames()) {
427-
Class<?> beanType = this.beanFactory.getType(beanName);
428-
if (beanType != null) {
429-
ClassHintUtils.registerProxyIfNecessary(beanType, runtimeHints);
430-
for (SmartInstantiationAwareBeanPostProcessor bpp : bpps) {
431-
Class<?> newBeanType = bpp.determineBeanType(beanType, beanName);
432-
if (newBeanType != beanType) {
433-
ClassHintUtils.registerProxyIfNecessary(newBeanType, runtimeHints);
434-
beanType = newBeanType;
435-
}
432+
BeanDefinition bd = getBeanDefinition(beanName);
433+
if (bd.isSingleton() && !bd.isLazyInit()) {
434+
preDetermineBeanType(beanName, bpps, runtimeHints);
435+
}
436+
else {
437+
lazyBeans.add(beanName);
438+
}
439+
}
440+
441+
// Second round: lazy singleton beans and scoped beans.
442+
for (String beanName : lazyBeans) {
443+
preDetermineBeanType(beanName, bpps, runtimeHints);
444+
}
445+
}
446+
447+
private void preDetermineBeanType(String beanName, List<SmartInstantiationAwareBeanPostProcessor> bpps,
448+
RuntimeHints runtimeHints) {
449+
450+
Class<?> beanType = this.beanFactory.getType(beanName);
451+
if (beanType != null) {
452+
ClassHintUtils.registerProxyIfNecessary(beanType, runtimeHints);
453+
for (SmartInstantiationAwareBeanPostProcessor bpp : bpps) {
454+
Class<?> newBeanType = bpp.determineBeanType(beanType, beanName);
455+
if (newBeanType != beanType) {
456+
ClassHintUtils.registerProxyIfNecessary(newBeanType, runtimeHints);
457+
beanType = newBeanType;
436458
}
437459
}
438460
}

0 commit comments

Comments
 (0)