spring系列——BeanNameGenerator接口(bean名字生成器)

目录

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的名字就是唯一的了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章