Skip to content

Commit

Permalink
Introduce BeanNameGenerator based on fully qualified class name
Browse files Browse the repository at this point in the history
Prior to this commit, Spring offered two top-level implementations of
the BeanNameGenerator strategy: DefaultBeanNameGenerator and
AnnotationBeanNameGenerator. The latter is used as the default bean
name generator for beans picked up via component scanning. In a typical
application, this strategy works well; however, if multiple component
scanned beans have the same simple class name (i.e., identical names
ignoring the package), a BeanDefinitionStoreException is thrown.

To address such naming conflicts, users of Spring have had to implement
a custom BeanNameGenerator based on the fully qualified class name of
such components.

Similar conflicts can arise with components registered via
configuration class imports (i.e., via @import), and
ConfigurationClassPostProcessor addresses this via an anonymous inner
class that extends AnnotationBeanNameGenerator but falls back to using
the fully qualified class name if an explicit bean name is not provided
via an annotation.

This commit extracts the implementation of
ConfigurationClassPostProcessor's internal BeanNameGenerator into a new
top-level FullyQualifiedAnnotationBeanNameGenerator class that can be
used to disambiguate between same-named components residing in
different packages that are picked up via component scanning. This bean
name generator can be configured via @componentscan's nameGenerator
attribute.

Closes gh-24114
  • Loading branch information
sbrannen committed Jan 7, 2020
1 parent e1fb4a1 commit b4c91e7
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 9 deletions.
Expand Up @@ -57,6 +57,7 @@
* @see org.springframework.stereotype.Service#value()
* @see org.springframework.stereotype.Controller#value()
* @see javax.inject.Named#value()
* @see FullyQualifiedAnnotationBeanNameGenerator
*/
public class AnnotationBeanNameGenerator implements BeanNameGenerator {

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -95,14 +95,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
* @since 5.2
* @see #setBeanNameGenerator
*/
public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR = new AnnotationBeanNameGenerator() {
@Override
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
return beanClassName;
}
};
public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR =
new FullyQualifiedAnnotationBeanNameGenerator();

private static final String IMPORT_REGISTRY_BEAN_NAME =
ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
Expand Down
@@ -0,0 +1,48 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.context.annotation;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.util.Assert;

/**
* An extension of {@code AnnotationBeanNameGenerator} that uses the fully qualified
* class name as the default bean name if an explicit bean name is not supplied via
* a supported type-level annotation such as {@code @Component} (see
* {@link AnnotationBeanNameGenerator} for details on supported annotations).
*
* <p>Note that an instance of this class is used by default for configuration-level
* import purposes; whereas, the default for component scanning purposes is a plain
* {@code AnnotationBeanNameGenerator}.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 5.2.3
* @see org.springframework.beans.factory.support.DefaultBeanNameGenerator
* @see AnnotationBeanNameGenerator
* @see ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR
*/
public class FullyQualifiedAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {

@Override
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
return beanClassName;
}

}

0 comments on commit b4c91e7

Please sign in to comment.