网站首页 > 开源技术 正文
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.BeanDefinitionReaderUtils
	public 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 name
				generatedBeanName = 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;
	}
总结流程:
- 生成流程分为前后两部分,前面生成的叫前缀,后面生成的叫后缀。
 - 读取待生成name实例的类名称,未必是运行时的实际类型。
 - 如果类型为空,则判断是否存在parent bean,如果存在,读取parent bean得name+"$child"
 - 如果parent bean 为空,那么判断是否存在factory bean ,如存在,factory bean name + “$created”.前缀生成完毕。
 - 如果前缀为空,直接抛出异常,没有可以定义这个bean的任何依据。
 - 前缀存在,判断是否为内部bean(innerBean,此处默认为false),如果是,最终为前缀+分隔符+十六进制的hashcode码。
 - 如果是顶级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<String, Set<String>> 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
     */
	@Nullable
	protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
	    /** 获取注解类元信息 */
		AnnotationMetadata amd = annotatedDef.getMetadata();
		/** 一个类存在多个注解,故类型为集合*/
		Set<String> types = amd.getAnnotationTypes();
		String beanName = null;
		for (String type : types) {
		    /** 获取该类型对应的属性 */
			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
			if (attributes != null) {
				Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
					Set<String> 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注解的:
- 读取所有注解类型
 - 便利所有注解类型,找到所有为Component、Service,Respository,Controller含有非空value属性的注解
 - 不多于一个个有效配置时生效,大于一个会抛出异常。(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();
    
猜你喜欢
- 2024-10-13 自己手写一个SpringMVC框架(springmvc框架搭建流程)
 - 2024-10-13 Restyle 来了!下一代 React 组件的样式技术
 - 2024-10-13 向工程腐化开炮 | proguard治理(向僵尸开炮工程师雇佣兵怎么得到)
 - 2024-10-13 Spring Boot 之 spring.factories
 - 2024-10-13 前端开发React18 - 组件(react 组件设计)
 - 2024-10-13 Android 混淆那些事儿(android混淆后怎么反编译)
 - 2024-10-13 一种 Table 统计行的实现方式(做表统计数据)
 - 2024-10-13 值得推荐的5种 瀑布流场景的实现原理解析
 - 2024-10-13 微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI
 - 2024-10-13 实时目标检测神器:YOLOv5的安装与使用详解
 
欢迎 你 发表评论:
- 1590℃北京那些看上去很牛的车牌们!(北京厉害车牌)
 - 1107℃2025年度视频去水印软件TOP5对比:哪款最值得用
 - 683℃《我的世界》不同版本的差异 ——新手向
 - 595℃新疆话里的“虫子”
 - 516℃中兴光猫 Telnet下设置大全(中兴光猫命令大全)
 - 514℃蓝牙设备配对失败的系统性解决方案与技术解析
 - 510℃未备份电脑文件数据恢复的七种方法
 - 488℃工艺管道常用英文缩写 英汉对照
 
- 最近发表
 
- 标签列表
 - 
- jdk (81)
 - putty (66)
 - rufus (78)
 - 内网穿透 (89)
 - okhttp (70)
 - powertoys (74)
 - windowsterminal (81)
 - netcat (65)
 - ghostscript (65)
 - veracrypt (65)
 - asp.netcore (70)
 - wrk (67)
 - aspose.words (80)
 - itk (80)
 - ajaxfileupload.js (66)
 - sqlhelper (67)
 - express.js (67)
 - phpmailer (67)
 - xjar (70)
 - redisclient (78)
 - wakeonlan (66)
 - tinygo (85)
 - startbbs (72)
 - webftp (82)
 - vsvim (79)
 
 

本文暂时没有评论,来添加一个吧(●'◡'●)