Spring源码分析(四)-Bean定义阶段细节之bean名称的生成策略

BeanNameGenerator

有两个实现版本,DefaultBeanNameGenerator和AnnotationBeanNameGenerator。其中DefaultBeanNameGenerator是给资源文件加载bean时使用(BeanDefinitionReader中使用);AnnotationBeanNameGenerator是为了处理注解生成bean name的情况。

DefaultBeanNameGenerator

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);   }}

DefaultBeanNameGenerator类将具体的处理方式委托给了,BeanDefinitionReaderUtils 中的generateBeanName(BeanDefinition, BeanDefinitionRegistry)方法处理。

//org.springframework.beans.factory.support.BeanDefinitionReaderUtilspublic static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {return generateBeanName(beanDefinition, registry, false);}//多指定了一个boolean型参数,是为了区分内部bean(innerBean)和顶级bean(top-level bean).public static String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)throws BeanDefinitionStoreException {//generatedBeanName定义为类前缀,读取bean的className,不一定是运行时的实际类型。String generatedBeanName = definition.getBeanClassName();//如果类名称为空if (generatedBeanName == null) { if (definition.getParentName() != null) {//读取bean的parent bean namegeneratedBeanName = definition.getParentName() + "$child";}else if (definition.getFactoryBeanName() != null) {//读取生成该bean的factoryBean name名称做前缀generatedBeanName = definition.getFactoryBeanName() + "$created";}}//generatedBeanName为空字符串,抛出异常if (!StringUtils.hasText(generatedBeanName)) {throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");}//当为内部bean时,调用系统底层的object唯一标识码生成if (isInnerBean) {// Inner bean: generate identity hashcode suffix.return generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);}//否则即为顶级bean,生成策略是前缀+循环数字,直到找到没有被注册的id作为后缀// Top-level bean: use plain class name with unique suffix if necessary.return uniqueBeanName(generatedBeanName, registry);}/**将给定bean名称转换为给定bean工厂的惟一bean名称,必要时附加惟一计数器作为后缀。*/public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {String id = beanName;int counter = -1;// Increase counter until the id is unique.String prefix = beanName + GENERATED_BEAN_NAME_SEPARATOR;while (counter == -1 || registry.containsBeanDefinition(id)) {counter++;id = prefix + counter;}return id;}

总结流程:

  1. 生成流程分为前后两部分,前面生成的叫前缀,后面生成的叫后缀。
  2. 读取待生成name实例的类名称,未必是运行时的实际类型。
  3. 如果类型为空,则判断是否存在parent bean,如果存在,读取parent bean得name+"$child"
  4. 如果parent bean 为空,那么判断是否存在factory bean ,如存在,factory bean name + “$created”.前缀生成完毕。
  5. 如果前缀为空,直接抛出异常,没有可以定义这个bean的任何依据。
  6. 前缀存在,判断是否为内部bean(innerBean,此处默认为false),如果是,最终为前缀+分隔符+十六进制的hashcode码。
  7. 如果是顶级bean(top-level bean ),则判断前缀+数字的bean是否已存在,循环查询,直到查询到没有使用的id为止。处理完成。

AnnotationBeanNameGenerator

public class AnnotationBeanNameGenerator implements BeanNameGenerator {   public static final AnnotationBeanNameGenerator INSTANCE = new AnnotationBeanNameGenerator();   private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";   private final Map> metaAnnotationTypesCache = new ConcurrentHashMap<>();   @Override   public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {        /**         * 判断是否是否是AnnotatedBeanDefinition的子类, AnnotatedBeanDefinition是BeanDefinition的一个子类         * 如果是AnnotatedBeanDefinition , 按照注解生成模式生成信息,否则生成默认的bean name         */      if (definition instanceof AnnotatedBeanDefinition) {         String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);         /** 保证生成的bean name 非空 */         if (StringUtils.hasText(beanName)) {            // Explicit bean name found.            return beanName;         }      }      // Fallback: generate a unique default bean name.      return buildDefaultBeanName(definition, registry);   }/**     * 从类的注解中包含value属性的注解生成一个bean name     * @param annotatedDef     * @return     */@Nullableprotected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {    /** 获取注解类元信息 */AnnotationMetadata amd = annotatedDef.getMetadata();/** 一个类存在多个注解,故类型为集合*/Set types = amd.getAnnotationTypes();String beanName = null;for (String type : types) {    /** 获取该类型对应的属性 */AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);if (attributes != null) {Set metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {Set result = amd.getMetaAnnotationTypes(key);return (result.isEmpty() ? Collections.emptySet() : result);});/** 判断注解类型是否包含value属性 */if (isStereotypeWithNameValue(type, metaTypes, 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 String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {return buildDefaultBeanName(definition);}protected String buildDefaultBeanName(BeanDefinition definition) {String beanClassName = definition.getBeanClassName();Assert.state(beanClassName != null, "No bean class name set");/** 根据传入字符串获取一个具体类名称,不含包路径,考虑cglib代理的类,做了一个特殊处理。 */String shortClassName = ClassUtils.getShortName(beanClassName);return Introspector.decapitalize(shortClassName);}}

总结:

生成bean name有两条处理线,使用AnnotationBeanDefinition注解和不使用的。

不使用AnnotationBeanDefinition注解:直接将类名(不含包名)改为驼峰形式作为bean name。

使用AnnotationBeanDefinition注解的:

  1. 读取所有注解类型
  2. 便利所有注解类型,找到所有为Component、Service,Respository,Controller含有非空value属性的注解
  3. 不多于一个个有效配置时生效,大于一个会抛出异常。(spring无法明确具体哪个生效)

如何自定义bean名称生成策略

AnnotationConfigApplicationContext在初始化的时候,可以设置bean生成策略器,放入单例池中;

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions方法中会进行bean策略器赋值,如果从单例池中根据默认名称获取到对应的beancel器则进行赋值,覆盖掉默认的bean策略器;

public static final String CONFIGURATION_BEAN_NAME_GENERATOR =      "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";/* Using short class names as default bean names by default. */private BeanNameGenerator componentScanBeanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;public static final AnnotationBeanNameGenerator INSTANCE = new AnnotationBeanNameGenerator();

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章