spring-bean命名规则
目录
Spring Bean拥有一个或多个标识符(identifiers),这些标识符在Bean所在的容器必须是唯一的。通常,一个Bean仅有一个标识符,如果需要额外的,可考虑使用别名(Alias)来扩充。在基于XML的配置元信息中,开发人员可用id或者name属性来规定 Bean的标识符。通常Bean的标识符由字母组成,允许出现特殊字符。如果要想引入Bean的别名的话,可在name属性使用半角逗号“,”或分号“;”来间隔。Bean的id或name属性并非必须制定,如果留空的话,容器会为Bean自动生成一个唯一的名称。Bean的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合Java的命名约定。
Spring内置生成beanName
Spring框架默认提供BeanNameGenerator接口来生成bean名称,默认实现方式有两种DefaultBeanNameGenerator
DefaultBeanNameGenerator
DefaultBeanNameGenerator默认通用BeanNameGenerator实现,具体源码实现:
public String generateBeanName(BeanDefinition definition,
BeanDefinitionRegistry registry) {
//调用生成beanName工具类
return BeanDefinitionReaderUtils.generateBeanName(definition, registry);
}
BeanDefinitionReaderUtils.generateBeanName具体实现
public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
return generateBeanName(beanDefinition, registry, false);
}
public static String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
throws BeanDefinitionStoreException {
//获取class名称
String generatedBeanName = definition.getBeanClassName();
//如果为空,从父类definition查找,如果查找到用父类+$child作为class名称
//父类definition查找不到,判断FactoryBeanName是否为空,不为空用FactoryBeanName+$created
if (generatedBeanName == null) {
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
else if (definition.getFactoryBeanName() != null) {
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
//判断class名称是否为空,为空报错
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
}
String id = generatedBeanName;
//判断否是内部类
if (isInnerBean) {
// Inner bean: generate identity hashcode suffix.
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
}
else {
// Top-level bean: use plain class name with unique suffix if necessary.
return uniqueBeanName(generatedBeanName, registry);
}
return id;
}
//生成beanName
public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
String id = beanName;
int counter = -1;
//判断bean id是否存在,如果存在一直循环至到不存在
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = beanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
return id;
}
AnnotationBeanNameGenerator基于注解扫描
对应的源码AnnotationBeanNameGenerator,具体实现如下:
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
//通过注解查找属性Value的值
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
//用class类名作为beanName
return buildDefaultBeanName(definition, registry);
}
针对@Bean注册的bean,如果未只能name属性,默认beanName为方法名
。
ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod方法
//关键代码
// Consider name and any aliases
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
总结
本文详细的介绍下Spring Bean命名规则和相关源码分析,希望本文能给你带来帮助。