diff --git a/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc b/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc
index e4e54668448..4e80edb40f3 100644
--- a/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc
+++ b/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc
@@ -556,18 +556,11 @@ Kotlin::
======
If you do not want to rely on the default bean-naming strategy, you can provide a custom
-bean-naming strategy. First, implement the
-{spring-framework-api}/beans/factory/support/BeanNameGenerator.html[`BeanNameGenerator`]
+bean-naming strategy. First, implement either the
+{spring-framework-api}/beans/factory/support/BeanNameGenerator.html[`BeanNameGenerator`] or
+{spring-framework-api}/context/annotation/ConfigurationBeanNameGenerator.html[`ConfigurationBeanNameGenerator`]
interface, and be sure to include a default no-arg constructor. Then, provide the fully
-qualified class name when configuring the scanner, as the following example annotation
-and bean definition show.
-
-TIP: If you run into naming conflicts due to multiple autodetected components having the
-same non-qualified class name (i.e., classes with identical names but residing in
-different packages), you may need to configure a `BeanNameGenerator` that defaults to the
-fully qualified class name for the generated bean name. The
-`FullyQualifiedAnnotationBeanNameGenerator` located in package
-`org.springframework.context.annotation` can be used for such purposes.
+qualified class name when configuring the scanner, as the following examples show.
[tabs]
======
@@ -602,6 +595,27 @@ Kotlin::
----
+[TIP]
+====
+If you run into naming conflicts due to multiple autodetected components having the same
+non-qualified class name (for example, classes with identical names but residing in
+different packages), you can configure a `BeanNameGenerator` that defaults to the
+fully-qualified class name for the generated bean name. The
+`FullyQualifiedAnnotationBeanNameGenerator` can be used for such purposes.
+
+As of Spring Framework 7.0, if you encounter naming conflicts among `@Bean` methods in
+`@Configuration` classes, you can alternatively configure a
+`ConfigurationBeanNameGenerator` that generates unique bean names for `@Bean` methods.
+The `FullyQualifiedConfigurationBeanNameGenerator` can be used to generate
+fully-qualified default bean names for `@Bean` methods without an explicit `name`
+attribute — for example, `com.example.MyConfig.myBean` for an `@Bean` method named
+`myBean()` declared in `@Configuration` class `com.example.MyConfig`.
+
+The `FullyQualifiedAnnotationBeanNameGenerator` and
+`FullyQualifiedConfigurationBeanNameGenerator` both reside in the
+`org.springframework.context.annotation` package.
+====
+
As a general rule, consider specifying the name with the annotation whenever other
components may be making explicit references to it. On the other hand, the
auto-generated names are adequate whenever the container is responsible for wiring.
diff --git a/framework-docs/modules/ROOT/pages/core/beans/java/bean-annotation.adoc b/framework-docs/modules/ROOT/pages/core/beans/java/bean-annotation.adoc
index e0811fc509b..1437b657f5a 100644
--- a/framework-docs/modules/ROOT/pages/core/beans/java/bean-annotation.adoc
+++ b/framework-docs/modules/ROOT/pages/core/beans/java/bean-annotation.adoc
@@ -4,10 +4,10 @@
`@Bean` is a method-level annotation and a direct analog of the XML `
The default is a {@link AnnotationBeanNameGenerator}. + *
The default is an {@link AnnotationBeanNameGenerator}. + * @see FullyQualifiedAnnotationBeanNameGenerator + * @see FullyQualifiedConfigurationBeanNameGenerator */ public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) { this.beanNameGenerator = diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java index 8bdf03e34fa..26b09c3b051 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java @@ -118,14 +118,20 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex /** * Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader} - * and/or {@link ClassPathBeanDefinitionScanner}, if any. - *
Default is {@link AnnotationBeanNameGenerator}. + * and/or {@link ClassPathBeanDefinitionScanner}. + *
Default is {@code AnnotationBeanNameGenerator}. + *
When processing {@link Configuration @Configuration} classes, a + * {@link ConfigurationBeanNameGenerator} (such as + * {@link FullyQualifiedConfigurationBeanNameGenerator}) also determines the + * default names for {@link Bean @Bean} methods without an explicit {@code name} + * attribute. *
Any call to this method must occur prior to calls to {@link #register(Class...)} * and/or {@link #scan(String...)}. * @see AnnotatedBeanDefinitionReader#setBeanNameGenerator * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator * @see AnnotationBeanNameGenerator * @see FullyQualifiedAnnotationBeanNameGenerator + * @see FullyQualifiedConfigurationBeanNameGenerator */ public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { this.reader.setBeanNameGenerator(beanNameGenerator); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Bean.java b/spring-context/src/main/java/org/springframework/context/annotation/Bean.java index f32df085292..22651d14b04 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/Bean.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/Bean.java @@ -45,10 +45,12 @@ import org.springframework.core.annotation.AliasFor; * *
While a {@link #name} attribute is available, the default strategy for * determining the name of a bean is to use the name of the {@code @Bean} method. - * This is convenient and intuitive, but if explicit naming is desired, the - * {@code name} attribute (or its alias {@code value}) may be used. Also note - * that {@code name} accepts an array of Strings, allowing for multiple names - * (i.e. a primary bean name plus one or more aliases) for a single bean. + * This default can be overridden by configuring a {@link ConfigurationBeanNameGenerator} + * — for example, {@link FullyQualifiedConfigurationBeanNameGenerator} for + * fully-qualified names. If explicit naming is desired for an individual bean, the + * {@code name} attribute (or its alias {@link #value}) may be used. Also note that + * {@code name} accepts an array of Strings, allowing for multiple names (i.e., a + * primary bean name plus one or more aliases) for a single bean. * *
* @Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
@@ -237,6 +239,9 @@ import org.springframework.core.annotation.AliasFor;
* @see org.springframework.stereotype.Component
* @see org.springframework.beans.factory.annotation.Autowired
* @see org.springframework.beans.factory.annotation.Value
+ * @see FullyQualifiedConfigurationBeanNameGenerator
+ * @see AnnotationConfigApplicationContext#setBeanNameGenerator
+ * @see ComponentScan#nameGenerator()
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@@ -255,10 +260,11 @@ public @interface Bean {
/**
* The name of this bean, or if several names, a primary bean name plus aliases.
- * If left unspecified, the name of the bean is the name of the annotated method.
- * If specified, the method name is ignored.
+ *
See the "Bean Names" section in the {@linkplain Bean class-level documentation}
+ * for details on how the bean name is determined if this attribute is left
+ * unspecified.
*
The bean name and aliases may also be configured via the {@link #value}
- * attribute if no other attributes are declared.
+ * attribute.
* @see #value
*/
@AliasFor("value")
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java
index 7c53ba9eba1..bd81ddf8988 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java
@@ -43,11 +43,11 @@ import org.springframework.util.PatternMatchUtils;
* or {@code ApplicationContext}).
*
*
Candidate classes are detected through configurable type filters. The
- * default filters include classes that are annotated with Spring's
- * {@link org.springframework.stereotype.Component @Component},
+ * default filters include classes that are annotated or meta-annotated with Spring's
+ * {@link org.springframework.stereotype.Component @Component} annotation, such as the
* {@link org.springframework.stereotype.Repository @Repository},
- * {@link org.springframework.stereotype.Service @Service}, or
- * {@link org.springframework.stereotype.Controller @Controller} stereotype.
+ * {@link org.springframework.stereotype.Service @Service}, and
+ * {@link org.springframework.stereotype.Controller @Controller} stereotypes.
*
*
Also supports JSR-330's {@link jakarta.inject.Named} annotations, if available.
*
@@ -204,8 +204,11 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
}
/**
- * Set the BeanNameGenerator to use for detected bean classes.
- *
Default is a {@link AnnotationBeanNameGenerator}.
+ * Set the {@link BeanNameGenerator} to use for detected bean classes.
+ *
Default is an {@code AnnotationBeanNameGenerator}.
+ * @see AnnotationBeanNameGenerator
+ * @see FullyQualifiedAnnotationBeanNameGenerator
+ * @see FullyQualifiedConfigurationBeanNameGenerator
*/
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator =
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java
index 621fd708e8b..857d2b5fe8f 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java
@@ -109,14 +109,18 @@ public @interface ComponentScan {
/**
* The {@link BeanNameGenerator} class to be used for naming detected components
* within the Spring container.
- *
The default value of the {@link BeanNameGenerator} interface itself indicates
+ *
The default value of the {@code BeanNameGenerator} interface itself indicates
* that the scanner used to process this {@code @ComponentScan} annotation should
* use its inherited bean name generator, for example, the default
* {@link AnnotationBeanNameGenerator} or any custom instance supplied to the
- * application context at bootstrap time.
+ * application context at bootstrap time. If a {@link ConfigurationBeanNameGenerator}
+ * is used (such as {@link FullyQualifiedConfigurationBeanNameGenerator}), it
+ * also affects the default names for {@link Bean @Bean} methods in
+ * {@link Configuration @Configuration} classes.
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
* @see AnnotationBeanNameGenerator
* @see FullyQualifiedAnnotationBeanNameGenerator
+ * @see FullyQualifiedConfigurationBeanNameGenerator
*/
Class extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java b/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
index 3733e2dfebe..95d683ca359 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
@@ -437,6 +437,8 @@ public @interface Configuration {
*
Alias for {@link Component#value}.
* @return the explicit component name, if any (or empty String otherwise)
* @see AnnotationBeanNameGenerator
+ * @see FullyQualifiedAnnotationBeanNameGenerator
+ * @see FullyQualifiedConfigurationBeanNameGenerator
*/
@AliasFor(annotation = Component.class)
String value() default "";
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
index 96a75f5f9a7..91e383489ed 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
@@ -242,12 +242,15 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
/**
* Set the {@link BeanNameGenerator} to be used when triggering component scanning
- * from {@link Configuration} classes and when registering {@link Import}'ed
- * configuration classes. The default is a standard {@link AnnotationBeanNameGenerator}
- * for scanned components (compatible with the default in {@link ClassPathBeanDefinitionScanner})
+ * from {@link Configuration @Configuration} classes and when registering
+ * {@link Import @Import}'ed configuration classes.
+ *
The default is a standard {@link AnnotationBeanNameGenerator} for scanned
+ * components (compatible with the default in {@link ClassPathBeanDefinitionScanner})
* and a variant thereof for imported configuration classes (using unique fully-qualified
* class names instead of standard component overriding).
- *
Note that this strategy does not apply to {@link Bean} methods.
+ *
If the supplied bean name generator is a {@link ConfigurationBeanNameGenerator}
+ * (such as {@link FullyQualifiedConfigurationBeanNameGenerator}), it also affects the
+ * default names for {@link Bean @Bean} methods in configuration classes.
*
This setter is typically only appropriate when configuring the post-processor as a
* standalone bean definition in XML, for example, not using the dedicated {@code AnnotationConfig*}
* application contexts or the {@code } element. Any bean name
@@ -255,6 +258,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
* @since 3.1.1
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
* @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
+ * @see AnnotationBeanNameGenerator
+ * @see FullyQualifiedAnnotationBeanNameGenerator
+ * @see FullyQualifiedConfigurationBeanNameGenerator
*/
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
diff --git a/spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java
index 837fdbd2688..4479df879f0 100644
--- a/spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java
+++ b/spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java
@@ -56,10 +56,8 @@ import org.springframework.web.context.ContextLoader;
* {@code registerBean(...)} methods available in a {@code GenericApplicationContext}.
* If you wish to register annotated component classes with a
* {@code GenericApplicationContext} in a web environment, you may use a
- * {@code GenericWebApplicationContext} with an
- * {@link org.springframework.context.annotation.AnnotatedBeanDefinitionReader
- * AnnotatedBeanDefinitionReader}. See the Javadoc for {@link GenericWebApplicationContext}
- * for details and an example.
+ * {@code GenericWebApplicationContext} with an {@link AnnotatedBeanDefinitionReader}.
+ * See the Javadoc for {@link GenericWebApplicationContext} for details and an example.
*
* To make use of this application context, the
* {@linkplain ContextLoader#CONTEXT_CLASS_PARAM "contextClass"} context-param for
@@ -116,9 +114,19 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
/**
* Set a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
* and/or {@link ClassPathBeanDefinitionScanner}.
- *
Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
+ *
Default is an {@link org.springframework.context.annotation.AnnotationBeanNameGenerator
+ * AnnotationBeanNameGenerator}.
+ *
When processing {@link org.springframework.context.annotation.Configuration @Configuration}
+ * classes, a {@link org.springframework.context.annotation.ConfigurationBeanNameGenerator
+ * ConfigurationBeanNameGenerator} (such as
+ * {@link org.springframework.context.annotation.FullyQualifiedConfigurationBeanNameGenerator
+ * FullyQualifiedConfigurationBeanNameGenerator}) also determines the default
+ * names for {@link org.springframework.context.annotation.Bean @Bean} methods
+ * without an explicit {@code name} attribute.
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
+ * @see org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator
+ * @see org.springframework.context.annotation.FullyQualifiedConfigurationBeanNameGenerator
*/
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = beanNameGenerator;