spring如何生成beanName的详解

spring如何生成beanName的

用了一年的spring,该系列的博文会有点偏总结吧
这篇文章主要讲的是spring 里的bean名称是如何产生的

通过Spring配置你的bean的几种方式

  • 第一种:配置文件
<bean class="com.zw.aop.test.MyAdvice" id="myAdvice"></bean>
  • 第二种:注解@Component,或者是带@Component的注解@Service等
@Service
//@Component
public class CacheLockProcessor {
    @Autowired
    private ShardedJedisPool shardedJedisPool;


}
  • 第三种:基于java的注解
@Configurable
public class Factory {
    @Bean
    public SayHello SayHello() {
        return new SayHelloImpl();

    }

}
  • 第四种/other 有基于jsr250/jsr330。具体不写了
本片文章主要是针对第一第二种场景:直接看spring源码是如何处理的:首先是看spring是如何读配置文件xml配置文件的bean的
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        List<String> aliases = new ArrayList<String>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr,         MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            beanName = aliases.remove(0);
            if (logger.isDebugEnabled()) {
                logger.debug("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            checkNameUniqueness(beanName, aliases, ele);
        }

        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        // Register an alias for the plain bean class name, if still possible,
                        // if the generator returned the class name plus a suffix.
                        // This is expected for Spring 1.2/2.0 backwards compatibility.
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Neither XML 'id' nor 'name' specified - " +
                                "using generated bean name [" + beanName + "]");
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }
  • 源码中可以看到aliases别名,一个bean可以有多个别名,用逗号分隔就好了。
  • 在xml文件里面配置bean的时候,如果自己配置了name和id属性,则就是自己所指定的名称。若只配置了id属性,则生成 的beanName就是id
  • 若id和name都没有配置,则会进以下方法来进行生成
if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
public static String generateBeanName(
            BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
            throws BeanDefinitionStoreException {

        String generatedBeanName = definition.getBeanClassName();
        if (generatedBeanName == null) {
            if (definition.getParentName() != null) {
                generatedBeanName = definition.getParentName() + "$child";
            }
            else if (definition.getFactoryBeanName() != null) {
                generatedBeanName = definition.getFactoryBeanName() + "$created";
            }
        }
        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.
            // Increase counter until the id is unique.
            int counter = -1;
            while (counter == -1 || registry.containsBeanDefinition(id)) {
                counter++;
                id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
            }
        }
        return id;
    }
  • 判断是否有父类,如果有父类,则名称为:definition.getParentName() + “$child”;
  • 判断是否有指定的工厂类,如果有,则为:definition.getFactoryBeanName() + “$created”;
  • 判断是否是innerBean:如果是,则名称为:className+GENERATED_BEAN_NAME_SEPARATO+ ObjectUtils.getIdentityHexString(definition);
 * @param isInnerBean whether the given bean definition will be registered
     * as inner bean or as top-level bean (allowing for special name generation
     * for inner beans versus top-level beans)
String org.springframework.beans.factory.support.BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR = "#"
  • 如果都不是,则是:
    id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
  • 第一个配置文件里的如果我配置name和id属性则生成的是:com.zw.aop.test.MyAdvice#0

若以注解的方式来进行生成。可以看以下代码

 */
public class AnnotationBeanNameGenerator implements BeanNameGenerator {

    private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";


    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        if (definition instanceof AnnotatedBeanDefinition) {
            String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
            if (StringUtils.hasText(beanName)) {
                // Explicit bean name found.
                return beanName;
            }
        }
        // Fallback: generate a unique default bean name.
        return buildDefaultBeanName(definition);
    }
  • 若在@Component里面配置了对应名称属性,则为配置的,若没有配置,则:
protected String buildDefaultBeanName(BeanDefinition definition) {
        String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
        return Introspector.decapitalize(shortClassName);
    }

直接由spring来进行创建,也就是类的名称,第一个字母该为小写

以上便是spring里bean名称的生成规则。

接下来的博文会继续介绍spring的源码,欢迎有兴趣的同学进行讨论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值