Compare commits

...

10 Commits

Author SHA1 Message Date
Kang Tae Hyun f85e998b0f
Merge f44e9899aa into 7e6874ad80 2025-10-08 00:41:18 +09:00
Sam Brannen 7e6874ad80 Polish @⁠Autowired section of the reference manual
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
Deploy Docs / Dispatch docs deployment (push) Waiting to run Details
2025-10-07 17:17:27 +02:00
Sam Brannen 097463e3b7 Remove outdated reference to JSR 305 in the reference documentation
Closes gh-35580
2025-10-07 17:10:40 +02:00
KNU-K f44e9899aa refactor: Extract bean definition skipping logic into a separate method
Signed-off-by: KNU-K <knukang334@gmail.com>
2025-09-19 02:38:53 +09:00
KNU-K 37bbf28830 refactor: Extract bean definition skipping logic into a separate method
Signed-off-by: KNU-K <knukang334@gmail.com>
2025-09-19 02:30:36 +09:00
KNU-K e381151824 refactor: Simplify bean processing logic in DefaultListableBeanFactory
Signed-off-by: KNU-K <knukang334@gmail.com>
2025-09-19 02:24:54 +09:00
KNU-K 5335ecceb4 refactor: Simplify bean processing logic in DefaultListableBeanFactory
Signed-off-by: KNU-K <knukang334@gmail.com>
2025-09-19 02:17:43 +09:00
KNU-K cd81381939 style: Improve code readability by adjusting else statement formatting
Signed-off-by: KNU-K <knukang334@gmail.com>
2025-09-19 00:54:31 +09:00
KNU-K 2ab2869539 fix the lint
Signed-off-by: KNU-K <knukang334@gmail.com>
2025-09-19 00:47:46 +09:00
KNU-K f7f164f8ee Refactor Improve performance by inducing hot path from the point of view of the jit compilor
Signed-off-by: KNU-K <knukang334@gmail.com>
2025-09-19 00:42:23 +09:00
2 changed files with 103 additions and 84 deletions

View File

@ -37,18 +37,18 @@ Kotlin::
---- ----
====== ======
[NOTE] [TIP]
==== ====
As of Spring Framework 4.3, an `@Autowired` annotation on such a constructor is no longer An `@Autowired` annotation on such a constructor is not necessary if the target bean
necessary if the target bean defines only one constructor to begin with. However, if defines only one constructor. However, if several constructors are available and there is
several constructors are available and there is no primary/default constructor, at least no primary or default constructor, at least one of the constructors must be annotated
one of the constructors must be annotated with `@Autowired` in order to instruct the with `@Autowired` in order to instruct the container which one to use. See the discussion
container which one to use. See the discussion on on xref:core/beans/annotation-config/autowired.adoc#beans-autowired-annotation-constructor-resolution[constructor resolution]
xref:core/beans/annotation-config/autowired.adoc#beans-autowired-annotation-constructor-resolution[constructor resolution] for details. for details.
==== ====
You can also apply the `@Autowired` annotation to _traditional_ setter methods, You can apply the `@Autowired` annotation to _traditional_ setter methods, as the
as the following example shows: following example shows:
[tabs] [tabs]
====== ======
@ -84,8 +84,8 @@ Kotlin::
---- ----
====== ======
You can also apply the annotation to methods with arbitrary names and multiple You can apply `@Autowired` to methods with arbitrary names and multiple arguments, as the
arguments, as the following example shows: following example shows:
[tabs] [tabs]
====== ======
@ -176,14 +176,15 @@ Kotlin::
==== ====
Make sure that your target components (for example, `MovieCatalog` or `CustomerPreferenceDao`) Make sure that your target components (for example, `MovieCatalog` or `CustomerPreferenceDao`)
are consistently declared by the type that you use for your `@Autowired`-annotated are consistently declared by the type that you use for your `@Autowired`-annotated
injection points. Otherwise, injection may fail due to a "no type match found" error at runtime. injection points. Otherwise, injection may fail due to a "no type match found" error at
runtime.
For XML-defined beans or component classes found via classpath scanning, the container For XML-defined beans or component classes found via classpath scanning, the container
usually knows the concrete type up front. However, for `@Bean` factory methods, you need usually knows the concrete type up front. However, for `@Bean` factory methods, you need
to make sure that the declared return type is sufficiently expressive. For components to make sure that the declared return type is sufficiently expressive. For components
that implement several interfaces or for components potentially referred to by their that implement several interfaces or for components potentially referred to by their
implementation type, consider declaring the most specific return type on your factory implementation type, declare the most specific return type on your factory method (at
method (at least as specific as required by the injection points referring to your bean). least as specific as required by the injection points referring to your bean).
==== ====
.[[beans-autowired-annotation-self-injection]]Self Injection .[[beans-autowired-annotation-self-injection]]Self Injection
@ -312,8 +313,8 @@ through `@Order` values in combination with `@Primary` on a single bean for each
==== ====
Even typed `Map` instances can be autowired as long as the expected key type is `String`. Even typed `Map` instances can be autowired as long as the expected key type is `String`.
The map values contain all beans of the expected type, and the keys contain the The map values are all beans of the expected type, and the keys are the corresponding
corresponding bean names, as the following example shows: bean names, as the following example shows:
[tabs] [tabs]
====== ======
@ -431,7 +432,7 @@ annotated constructor does not have to be public.
==== ====
Alternatively, you can express the non-required nature of a particular dependency Alternatively, you can express the non-required nature of a particular dependency
through Java 8's `java.util.Optional`, as the following example shows: through Java's `java.util.Optional`, as the following example shows:
[source,java,indent=0,subs="verbatim,quotes"] [source,java,indent=0,subs="verbatim,quotes"]
---- ----
@ -445,8 +446,8 @@ through Java 8's `java.util.Optional`, as the following example shows:
---- ----
You can also use a parameter-level `@Nullable` annotation (of any kind in any package -- You can also use a parameter-level `@Nullable` annotation (of any kind in any package --
for example, `javax.annotation.Nullable` from JSR-305) or just leverage Kotlin built-in for example, `org.jspecify.annotations.Nullable` from JSpecify) or just leverage Kotlin's
null-safety support: built-in null-safety support:
[tabs] [tabs]
====== ======
@ -477,13 +478,6 @@ Kotlin::
---- ----
====== ======
[NOTE]
====
A type-level `@Nullable` annotation such as from JSpecify is not supported in Spring
Framework 6.2 yet. You need to upgrade to Spring Framework 7.0 where the framework
detects type-level annotations and consistently declares JSpecify in its own codebase.
====
You can also use `@Autowired` for interfaces that are well-known resolvable You can also use `@Autowired` for interfaces that are well-known resolvable
dependencies: `BeanFactory`, `ApplicationContext`, `Environment`, `ResourceLoader`, dependencies: `BeanFactory`, `ApplicationContext`, `Environment`, `ResourceLoader`,
`ApplicationEventPublisher`, and `MessageSource`. These interfaces and their extended `ApplicationEventPublisher`, and `MessageSource`. These interfaces and their extended
@ -528,5 +522,6 @@ class MovieRecommender {
The `@Autowired`, `@Inject`, `@Value`, and `@Resource` annotations are handled by Spring The `@Autowired`, `@Inject`, `@Value`, and `@Resource` annotations are handled by Spring
`BeanPostProcessor` implementations. This means that you cannot apply these annotations `BeanPostProcessor` implementations. This means that you cannot apply these annotations
within your own `BeanPostProcessor` or `BeanFactoryPostProcessor` types (if any). within your own `BeanPostProcessor` or `BeanFactoryPostProcessor` types (if any).
These types must be 'wired up' explicitly by using XML or a Spring `@Bean` method. These types must be 'wired up' explicitly by using XML or a Spring `@Bean` method.
==== ====

View File

@ -614,93 +614,117 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>(); List<String> result = new ArrayList<>();
// Check all bean definitions. processBeanDefinitions(result, type, includeNonSingletons, allowEagerInit);
processManualSingletons(result, type, includeNonSingletons);
return StringUtils.toStringArray(result);
}
private void processBeanDefinitions(List<String> result, ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
for (String beanName : this.beanDefinitionNames) { for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name is not defined as alias for some other bean. if (isAlias(beanName)) {
if (!isAlias(beanName)) { continue;
try { }
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete. try {
if (!mbd.isAbstract() && (allowEagerInit || RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) { // cache merged bean definition
boolean isFactoryBean = isFactoryBean(beanName, mbd); boolean isAbstract = mbd.isAbstract();
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); boolean hasBeanClass = mbd.hasBeanClass();
boolean matchFound = false; boolean isLazyInit = mbd.isLazyInit();
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName)); String factoryBeanName = mbd.getFactoryBeanName();
boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit()); BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
if (!isFactoryBean) {
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) { if (shouldSkipBeanDefinition(isAbstract, allowEagerInit, hasBeanClass, isLazyInit, factoryBeanName)) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); continue;
} }
}
else { boolean isFactoryBean = isFactoryBean(beanName, mbd);
if (includeNonSingletons || isNonLazyDecorated) { boolean matchFound = false;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
} boolean isNonLazyDecorated = (dbd != null && !isLazyInit);
else if (allowFactoryBeanInit) {
// Type check before singleton check, avoiding FactoryBean instantiation if (!isFactoryBean && (includeNonSingletons || isSingleton(beanName, mbd, dbd))) {
// for early FactoryBean.isSingleton() calls on non-matching beans. matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit) && }
isSingleton(beanName, mbd, dbd); else {
} if (includeNonSingletons || isNonLazyDecorated) {
if (!matchFound) { matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
// In case of FactoryBean, try to match FactoryBean instance itself next. }
beanName = FACTORY_BEAN_PREFIX + beanName; else if (allowFactoryBeanInit) {
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) { matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit) &&
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); isSingleton(beanName, mbd, dbd);
} }
}
if (!matchFound) {
String factoryBeanFullName = FACTORY_BEAN_PREFIX + beanName;
if (includeNonSingletons || isSingleton(factoryBeanFullName, mbd, dbd)) {
matchFound = isTypeMatch(factoryBeanFullName, type, allowFactoryBeanInit);
} }
if (matchFound) { if (matchFound) {
result.add(beanName); result.add(factoryBeanFullName);
continue;
} }
} }
} }
catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
if (allowEagerInit) { if (matchFound) {
throw ex; result.add(beanName);
}
// Probably a placeholder: let's ignore it for type matching purposes.
LogMessage message = (ex instanceof CannotLoadBeanClassException ?
LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName));
logger.trace(message, ex);
// Register exception, in case the bean was accidentally unresolvable.
onSuppressedException(ex);
}
catch (NoSuchBeanDefinitionException ex) {
// Bean definition got removed while we were iterating -> ignore.
} }
} }
catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
if (allowEagerInit) {
throw ex;
}
LogMessage message = (ex instanceof CannotLoadBeanClassException ?
LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName));
logger.trace(message, ex);
onSuppressedException(ex);
}
catch (NoSuchBeanDefinitionException ex) {
// Bean definition got removed while we were iterating -> ignore
}
} }
}
// Check manually registered singletons too. private void processManualSingletons(List<String> result, ResolvableType type, boolean includeNonSingletons) {
for (String beanName : this.manualSingletonNames) { for (String beanName : this.manualSingletonNames) {
try { try {
// In case of FactoryBean, match object created by FactoryBean.
if (isFactoryBean(beanName)) { if (isFactoryBean(beanName)) {
if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) { if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
result.add(beanName); result.add(beanName);
// Match found for this bean: do not match FactoryBean itself anymore.
continue; continue;
} }
// In case of FactoryBean, try to match FactoryBean itself next.
beanName = FACTORY_BEAN_PREFIX + beanName; beanName = FACTORY_BEAN_PREFIX + beanName;
} }
// Match raw bean instance (might be raw FactoryBean).
if (isTypeMatch(beanName, type)) { if (isTypeMatch(beanName, type)) {
result.add(beanName); result.add(beanName);
} }
} }
catch (NoSuchBeanDefinitionException ex) { catch (NoSuchBeanDefinitionException ex) {
// Shouldn't happen - probably a result of circular reference resolution...
logger.trace(LogMessage.format( logger.trace(LogMessage.format(
"Failed to check manually registered singleton with name '%s'", beanName), ex); "Failed to check manually registered singleton with name '%s'", beanName), ex);
} }
} }
}
return StringUtils.toStringArray(result); private boolean shouldSkipBeanDefinition(boolean isAbstract, boolean allowEagerInit,
boolean hasBeanClass, boolean isLazyInit, @Nullable String factoryBeanName) {
if (isAbstract) {
return true;
}
if (!allowEagerInit) {
boolean needsEagerInit = (!hasBeanClass && isLazyInit && !isAllowEagerClassLoading()) ||
requiresEagerInitForType(factoryBeanName);
if (needsEagerInit) {
return true;
}
}
return false;
} }
private boolean isSingleton(String beanName, RootBeanDefinition mbd, @Nullable BeanDefinitionHolder dbd) { private boolean isSingleton(String beanName, RootBeanDefinition mbd, @Nullable BeanDefinitionHolder dbd) {