Spring Bean 默认命名策略源码分析


title: Spring Bean 命名源码分析
date: 2021-01-19 23:05:22
tags: Spring-Framework

前言

Spring在进行Bean注册的时候需要有一个唯一标识,这个标识也成为BeanName。在进行Bean注册时,这个id并不必填项,它可以由Spring自动生成。下面就来讨论其中一种生成策略。

BeanNameGenerator

org.springframework.beans.factory.support.BeanNameGenerator这个接口就是Spring Bean名称生成器。我们看下源码

public interface BeanNameGenerator {

    /**
     * Generate a bean name for the given bean definition.
     * @param definition the bean definition to generate a name for
     * @param registry the bean definition registry that the given definition
     * is supposed to be registered with
     * @return the generated bean name
     */
    String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);

}

该接口只定义了一个方法用于获取BeanName,需要传入BeanDefinition BeanDefinitionRegistry

这里简单说明下为什么需要这两个参数

  • BeanDefinition用于获取该Bean的ClassName
  • BeanDefinitionRegistry用于判断生成的BeanName是否已注册,如果已注册会附加类似#0这样的序列号

BeanNameGenerator 实现类

这个接口有两个实现 DefaultBeanNameGenerator AnnotationBeanNameGenerator

这里我们暂时只讨论前者,这个名称生成器的默认实现

DefaultBeanNameGenerator

/**
 * Default implementation of the {@link BeanNameGenerator} interface, delegating to
 * {@link BeanDefinitionReaderUtils#generateBeanName(BeanDefinition, BeanDefinitionRegistry)}.
 *
 * @author Juergen Hoeller
 * @since 2.0.3
 */
public class DefaultBeanNameGenerator implements BeanNameGenerator {

    /**
     * A convenient constant for a default {@code DefaultBeanNameGenerator} instance,
     * as used for {@link AbstractBeanDefinitionReader} setup.
     * @since 5.2
     */
    public static final DefaultBeanNameGenerator INSTANCE = new DefaultBeanNameGenerator();

    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        return BeanDefinitionReaderUtils.generateBeanName(definition, registry);
    }

}

这个默认实现类,存在一个单例对象,看doc是5.2才加的,因为要兼容之前的版本,所以没有私有化构造器

该实现类,委托给BeanDefinitionReaderUtils实现功能

BeanDefinitionReaderUtils

真正的实现是这个工具类

    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 with unique suffix if necessary.
            return uniqueBeanName(generatedBeanName, registry);
        }
        return id;
    }

这里可以看出id是直接取的Bean的ClassName,如果是非内部类,会做唯一性校验

    public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
        String id = beanName;
        int counter = -1;

        // Increase counter until the id is unique.
        while (counter == -1 || registry.containsBeanDefinition(id)) {
            counter++;
            id = beanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
        }
        return id;
    }

每个beanName都会被加上#0,然后去容器里面看是否被注册,如果被组成则序号加一

写得比较粗糙,有时间会详细写一下

上一篇:从源代码分析Android-Universal-Image-Loader的缓存处理机制


下一篇:Maven项目中无法找到 xml文件或 properties文件等配置文件的解决方法