当一个组件作为扫描过程的一部分被自动检测到时,它的 Bean 名称由该扫描器已知的BeanNameGenerator 策略生成。默认情况下,任何包含名称值的 Spring 原型注解(@Component
、@Repository
、@Service
和 @Controller
)都会向相应的 Bean 定义提供该名称。
如果这样的注解 不包含名称值,或者对于任何其他检测到的组件(比如那些由自定义过滤器发现的组件),默认的 Bean 类名称生成器会返回未加大写的非限定类名称。例如,如果检测到以下组件类,其名称将是 myMovieLister 和 movieFinderImpl。
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
如果你不想依赖默认的 Bean-naming 策略,你可以提供一个自定义的 Bean-naming 策略。首先,实现BeanNameGenerator 接口,并确保包含一个默认的无参数构造函数。然后,在配置扫描器时提供完全合格的类名,正如下面的注解和 Bean 定义的例子所示。
:::tips 如果你由于多个自动检测的组件具有相同的非限定类名称(即具有相同名称的类,但驻留在不同的包中)而遇到命名冲突,你可能需要配置一个 BeanNameGenerator,默认为生成的 Bean 名称为完全限定的类名称。从 Spring Framework 5.2.3 开始,位于包 org.springframework.context.annotation 中的FullyQualifiedAnnotationBeanNameGenerator 可以用于此类目的。 :::
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
自定义名称策略如下,将类路径作为名称:
package cn.mrcode.study.springdocsread.web;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
/**
* @author mrcode
*/
public class MyBeanNameGenerator implements BeanNameGenerator {
/**
* 为给定的 bean 定义生成一个 bean 名称。
* @param definition bean 定义
* @param registry 该 bean 注册的注册表
* @return
*/
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
// 返回 bean 的路径 cn.mrcode.study.springdocsread.web.Config
final String beanClassName = definition.getBeanClassName();
return beanClassName;
}
}
默认的策略对于 cn.mrcode.study.springdocsread.web.Config
产生的 Config 对象的 bean 为 Config,而我们上面自定义产生的名称就是他的类路径 cn.mrcode.study.springdocsread.web.Config
:::tips
另外上面提到过了 5.2.3 版本开始,Spring 提供了一个全路径名称的策略类 FullyQualifiedAnnotationBeanNameGenerator
:::
作为一般规则,每当其他组件可能对注解进行显式引用时,请考虑使用注解指定名称。另一方面,只要容器负责连接,自动生成的名称就足够了。