目录
1、BeanNameGenerator 接口
2、AnnotationBeanNameGenerator 类
3、DefaultBeanNameGenerator 类
spring容器是通过bean Name去管理着大量的bean,而且不出错。
首先看看spring是如何为每个bean生成名字的,BeanNameGenerator接口是bean名字生成器的入口,下面是类图:
1、BeanNameGenerator 接口
就一个方法,为某个bean生成名字,参数为BeanDefinition 和 BeanDefinitionRegistry 类型。此处可以反映出spring需要的bean结构是BeanDefinition。
public interface BeanNameGenerator {
String generateBeanName(BeanDefinition var1, BeanDefinitionRegistry var2);
}
2、AnnotationBeanNameGenerator 类
从这个类名基本可以知道,这个类是为那些用注解方式的bean生成名字。暂时不作介绍。
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
//@Component注解(这个功能类)的类名
private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
public AnnotationBeanNameGenerator() { }
//生成bean的名字,实现了接口中的方法
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = this.determineBeanNameFromAnnotation((AnnotatedBeanDefinition)definition);
if (StringUtils.hasText(beanName)) {
return beanName;
}
}
return this.buildDefaultBeanName(definition, registry);
}
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
AnnotationMetadata amd = annotatedDef.getMetadata();
Set<String> types = amd.getAnnotationTypes();
String beanName = null;
Iterator var5 = types.iterator();
while(var5.hasNext()) {
String type = (String)var5.next();
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
if (attributes != null && this.isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String)value;
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
return beanName;
}
protected boolean isStereotypeWithNameValue(String annotationType, Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes) {
boolean isStereotype = annotationType.equals("org.springframework.stereotype.Component") || metaAnnotationTypes.contains("org.springframework.stereotype.Component") || annotationType.equals("javax.annotation.ManagedBean") || annotationType.equals("javax.inject.Named");
return isStereotype && attributes != null && attributes.containsKey("value");
}
protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return this.buildDefaultBeanName(definition);
}
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}
}
3、DefaultBeanNameGenerator 类
下面是源码,就一个方法实现。
public class DefaultBeanNameGenerator implements BeanNameGenerator {
public DefaultBeanNameGenerator() {}
//实现接口方法,为某个bean生成名字
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
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 {
//获取bean的类名(全路径类名)
String generatedBeanName = definition.getBeanClassName();
//如果类名为空时
if (generatedBeanName == null) {
//bean的父bean名字不为空时
if (definition.getParentName() != null) {
//此bean的名字就为:父bean名+$child
generatedBeanName = definition.getParentName() + "$child";
}
//bean的工厂bean名字不为空时
else if (definition.getFactoryBeanName() != null) {
//此bean的名字就为:生产它的工厂bean名+$created
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
//bean的名字为null、“”、“ ”时,抛出异常
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither 'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
}
//此处isInnerBean 为false
else if (isInnerBean) {
String id = generatedBeanName + "#" + ObjectUtils.getIdentityHexString(definition);
return id;
} else {
//返回bean的名字
return uniqueBeanName(generatedBeanName, registry);
}
}
继续追踪,看看uniqueBeanName()方法:
这个方法的意思是:如果generateBeanName()方法生成的bean名字,已经被注册了(即已经存在了),那么就在名字后加上#和数字,比如hehe名字已经存在了,那么此时如果generateBeanName()方法生成的名字还是hehe,那么此时就在hehe后面加上#0(hehe#0),就是#后的数字递增,来区分,因为bean的名字必须唯一。
public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
String id = beanName;
for(int counter = -1; counter == -1 || registry.containsBeanDefinition(id); id = beanName + "#" + counter) {
++counter;
}
return id;
}
bean名字生成的流程总结:bean将自己的全路径类名作为自己的bean名字,如果没有类名,那就看是否有父bean,如果有,假设父bean名字为hehe,那么就用hehe$child作为此子bean的名字,如果没有父bean,那就看bean的工厂bean的名字,如果有,假设工厂bean名字为haha,那么bean的名字就是haha$created,如果没有工厂,那就报错“既没有自己的类名、也没有父bean类名、也没有工厂bean类名”。不管最终用的是哪一个的名字,对这个名字进行唯一性检查,如果名字重复了(已经有这个名字存在了),那就在名字后面+#+数字,这样,每个bean的名字就是唯一的了。