Browse Source

Improve documentation for FullyQualifiedConfigurationBeanNameGenerator

This commit documents FullyQualifiedConfigurationBeanNameGenerator in
related Javadoc and in the reference manual.

See gh-33448
Closes gh-36455
pull/36461/head
Sam Brannen 7 days ago
parent
commit
04313f062e
  1. 36
      framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc
  2. 23
      framework-docs/modules/ROOT/pages/core/beans/java/bean-annotation.adoc
  3. 1
      spring-beans/src/main/java/org/springframework/beans/factory/support/BeanNameGenerator.java
  4. 4
      spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java
  5. 10
      spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java
  6. 20
      spring-context/src/main/java/org/springframework/context/annotation/Bean.java
  7. 15
      spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java
  8. 8
      spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java
  9. 2
      spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
  10. 14
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
  11. 18
      spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java

36
framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc

@ -556,18 +556,11 @@ Kotlin:: @@ -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:: @@ -602,6 +595,27 @@ Kotlin::
</beans>
----
[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.

23
framework-docs/modules/ROOT/pages/core/beans/java/bean-annotation.adoc

@ -4,10 +4,10 @@ @@ -4,10 +4,10 @@
`@Bean` is a method-level annotation and a direct analog of the XML `<bean/>` element.
The annotation supports some of the attributes offered by `<bean/>`, such as:
* xref:core/beans/definition.adoc#beans-beanname[name]
* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-initializingbean[init-method]
* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-disposablebean[destroy-method]
* xref:core/beans/dependencies/factory-autowire.adoc[autowiring]
* `name`.
You can use the `@Bean` annotation in a `@Configuration`-annotated or in a
`@Component`-annotated class.
@ -17,9 +17,10 @@ You can use the `@Bean` annotation in a `@Configuration`-annotated or in a @@ -17,9 +17,10 @@ You can use the `@Bean` annotation in a `@Configuration`-annotated or in a
== Declaring a Bean
To declare a bean, you can annotate a method with the `@Bean` annotation. You use this
method to register a bean definition within an `ApplicationContext` of the type
specified as the method's return value. By default, the bean name is the same as
the method name. The following example shows a `@Bean` method declaration:
method to register a bean definition within an `ApplicationContext` of the type specified
by the method's return type. By default, the bean name is the same as the method name
(unless a different xref:#beans-java-customizing-bean-naming[bean name generator] is
configured). The following example shows a `@Bean` method declaration:
[tabs]
======
@ -126,7 +127,7 @@ Kotlin:: @@ -126,7 +127,7 @@ Kotlin::
----
======
However, this limits the visibility for advance type prediction to the specified
However, this limits the visibility for advanced type prediction to the specified
interface type (`TransferService`). Then, with the full type (`TransferServiceImpl`)
known to the container only once the affected singleton bean has been instantiated.
Non-lazy singleton beans get instantiated according to their declaration order,
@ -473,8 +474,15 @@ Kotlin:: @@ -473,8 +474,15 @@ Kotlin::
== Customizing Bean Naming
By default, configuration classes use a `@Bean` method's name as the name of the
resulting bean. This functionality can be overridden, however, with the `name` attribute,
as the following example shows:
resulting bean. However, as of Spring Framework 7.0, you can change this default strategy
by configuring a custom
{spring-framework-api}/context/annotation/ConfigurationBeanNameGenerator.html[`ConfigurationBeanNameGenerator`]
when bootstrapping the context or configuring component scanning. For example,
{spring-framework-api}/context/annotation/FullyQualifiedConfigurationBeanNameGenerator.html[`FullyQualifiedConfigurationBeanNameGenerator`]
can be used to generate fully-qualified default bean names for `@Bean` methods without an
explicit `name` attribute. For individual `@Bean` methods, the default or
generator-derived name can be overridden with the `name` attribute, as the following
example shows:
[tabs]
======
@ -505,6 +513,7 @@ Kotlin:: @@ -505,6 +513,7 @@ Kotlin::
----
======
NOTE: `@Bean("myThing")` is equivalent to `@Bean(name = "myThing")`.
[[beans-java-bean-aliasing]]
== Bean Aliasing

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

@ -23,6 +23,7 @@ import org.springframework.beans.factory.config.BeanDefinition; @@ -23,6 +23,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
*
* @author Juergen Hoeller
* @since 2.0.3
* @see org.springframework.context.annotation.ConfigurationBeanNameGenerator
*/
public interface BeanNameGenerator {

4
spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java

@ -109,7 +109,9 @@ public class AnnotatedBeanDefinitionReader { @@ -109,7 +109,9 @@ public class AnnotatedBeanDefinitionReader {
/**
* Set the {@code BeanNameGenerator} to use for detected bean classes.
* <p>The default is a {@link AnnotationBeanNameGenerator}.
* <p>The default is an {@link AnnotationBeanNameGenerator}.
* @see FullyQualifiedAnnotationBeanNameGenerator
* @see FullyQualifiedConfigurationBeanNameGenerator
*/
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator =

10
spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java

@ -118,14 +118,20 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex @@ -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.
* <p>Default is {@link AnnotationBeanNameGenerator}.
* and/or {@link ClassPathBeanDefinitionScanner}.
* <p>Default is {@code AnnotationBeanNameGenerator}.
* <p>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.
* <p>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);

20
spring-context/src/main/java/org/springframework/context/annotation/Bean.java

@ -45,10 +45,12 @@ import org.springframework.core.annotation.AliasFor; @@ -45,10 +45,12 @@ import org.springframework.core.annotation.AliasFor;
*
* <p>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}
* &mdash; 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.
*
* <pre class="code">
* &#064;Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
@ -237,6 +239,9 @@ import org.springframework.core.annotation.AliasFor; @@ -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 { @@ -255,10 +260,11 @@ public @interface Bean {
/**
* The name of this bean, or if several names, a primary bean name plus aliases.
* <p>If left unspecified, the name of the bean is the name of the annotated method.
* If specified, the method name is ignored.
* <p>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.
* <p>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")

15
spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java

@ -43,11 +43,11 @@ import org.springframework.util.PatternMatchUtils; @@ -43,11 +43,11 @@ import org.springframework.util.PatternMatchUtils;
* or {@code ApplicationContext}).
*
* <p>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.
*
* <p>Also supports JSR-330's {@link jakarta.inject.Named} annotations, if available.
*
@ -204,8 +204,11 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo @@ -204,8 +204,11 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
}
/**
* Set the BeanNameGenerator to use for detected bean classes.
* <p>Default is a {@link AnnotationBeanNameGenerator}.
* Set the {@link BeanNameGenerator} to use for detected bean classes.
* <p>Default is an {@code AnnotationBeanNameGenerator}.
* @see AnnotationBeanNameGenerator
* @see FullyQualifiedAnnotationBeanNameGenerator
* @see FullyQualifiedConfigurationBeanNameGenerator
*/
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator =

8
spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java

@ -109,14 +109,18 @@ public @interface ComponentScan { @@ -109,14 +109,18 @@ public @interface ComponentScan {
/**
* The {@link BeanNameGenerator} class to be used for naming detected components
* within the Spring container.
* <p>The default value of the {@link BeanNameGenerator} interface itself indicates
* <p>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;

2
spring-context/src/main/java/org/springframework/context/annotation/Configuration.java

@ -437,6 +437,8 @@ public @interface Configuration { @@ -437,6 +437,8 @@ public @interface Configuration {
* <p>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 "";

14
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

@ -242,12 +242,15 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo @@ -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.
* <p>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).
* <p>Note that this strategy does <em>not</em> apply to {@link Bean} methods.
* <p>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.
* <p>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 <context:annotation-config>} element. Any bean name
@ -255,6 +258,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo @@ -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");

18
spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java

@ -56,10 +56,8 @@ import org.springframework.web.context.ContextLoader; @@ -56,10 +56,8 @@ import org.springframework.web.context.ContextLoader;
* {@code registerBean(...)} methods available in a {@code GenericApplicationContext}.
* If you wish to register annotated <em>component classes</em> 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.
*
* <p>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 @@ -116,9 +114,19 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
/**
* Set a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
* and/or {@link ClassPathBeanDefinitionScanner}.
* <p>Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
* <p>Default is an {@link org.springframework.context.annotation.AnnotationBeanNameGenerator
* AnnotationBeanNameGenerator}.
* <p>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;

Loading…
Cancel
Save