目錄
2、AnnotationBeanNameGenerator 類
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的名字就是唯一的了。