探讨一下spring中bean名字的生成规则
  TID0Jm6s2KFF 2023年11月09日 45 0

注入的controller属于内部类,并继承了某个类,一开始以为其名字也是类名首字母小写的字符串,结果错了,实际是父类首字母小写 + "." + 当前类名,下面我们一起探究一下,spring的bean名字生成规则。


spring属性注入查找属性值是在org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates方法。

其中生成属性名称调用的代码是

String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
		this, requiredType, true, descriptor.isEager());

该方法如下

public static String[] beanNamesForTypeIncludingAncestors(
		ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {

	Assert.notNull(lbf, "ListableBeanFactory must not be null");
	String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
	if (lbf instanceof HierarchicalBeanFactory hbf) {
		if (hbf.getParentBeanFactory() instanceof ListableBeanFactory pbf) {
			String[] parentResult = beanNamesForTypeIncludingAncestors(
					pbf, type, includeNonSingletons, allowEagerInit);
			result = mergeNamesWithParent(result, parentResult, hbf);
		}
	}
	return result;
}
  • 可以发现最终还是调用的org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeanNamesForType(java.lang.Class<?>, boolean, boolean)方法生成的属性名称
  • 该方法又调用了org.springframework.beans.factory.support.DefaultListableBeanFactory#doGetBeanNamesForType
  • doGetBeanNamesForType方法直接遍历beanDefinitionNames和manualSingletonNames两个缓存查找的

那么beanDefinitionNames又是什么时候初始化的呢?查找可以发现在org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition方法初始化了该缓存。

该缓存是在容器初始化的时候通过AnnotatedBeanDefinitionReader或者XmlBeanDefinitionReader,GroovyBeanDefinitionReader,PropertiesBeanDefinitionReader等注入进去的。

这里我们直接看AnnotatedBeanDefinitionReader。其核心注册逻辑如下

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		abd.setInstanceSupplier(supplier);
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		if (customizers != null) {
			for (BeanDefinitionCustomizer customizer : customizers) {
				customizer.customize(abd);
			}
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

bean名称最终是通过AnnotationBeanNameGenerator生成的。步骤如下

  1. 先查看注解是否指定了bean名称,有指定的话用指定的
  2. 在生成默认的bean名称(因为这儿是默认生成的,为了唯一,会把父类名这些都加上)

总结

spring里面通过大量设计良好,职责清晰的接口,保证了代码解耦和扩展性。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月09日 0

暂无评论

推荐阅读
TID0Jm6s2KFF