SpringBoot扩展篇:Spring注入 @Autowired @Resource

news2024/11/26 14:58:05

Spring注入 @Autowired & @Resource

    • 1. 概述
      • 1.1 职责
      • 1.2 流程概述
    • 2. Demo
    • 3. AutowiredAnnotationBeanPostProcessor注册
    • 4. 注册元数据
      • 4.1 AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
      • 4.2 AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
      • 4.3 AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
    • 5. 字段注入逻辑
      • 5.1 AutowiredAnnotationBeanPostProcessor#postProcessProperties
      • 5.2 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
      • 5.3 解决依赖关系 DefaultListableBeanFactory#doResolveDependency
      • 5.4 Autowired注入逻辑总结
    • 6. @Resource注入方式
      • 6.1 Demo
      • 6.2 Resource注入逻辑
      • 6.3 CommonAnnotationBeanPostProcessor#autowireResource
      • 6.4 结论

1. 概述

1.1 职责

@Autowired注入是由AutowiredAnnotationBeanPostProcessor完成的。
@Resource注入是由CommonAnnotationBeanPostProcessor完成的。
由于两种方式代码重复率太高,原理基本一致,下面我们主要以AutowiredAnnotationBeanPostProcessor源码分析为主。

1.2 流程概述

AutowiredAnnotationBeanPostProcessor负责属性、方法的注入。
分为两个流程:

  1. 注册元数据:先将要注入的字段和方法组成元数据,放入缓存中。
  2. 赋值:通过缓存中的描述信息从beanFactory中获取bean,字段和方法注入。

2. Demo

AutoObjectA

@Component
public class AutoObjectA {

    @Autowired
    private AutoObjectB autoObjectB;
    
}

AutoObjectB

@Component
public class AutoObjectB {

}

3. AutowiredAnnotationBeanPostProcessor注册

在创建AnnotationConfigServletWebServerApplicationContext的时候,就已经注册了AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor。
SpringBoot 源码解析2:启动流程

AnnotationConfigUtils#registerAnnotationConfigProcessors

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}

	return beanDefs;
}

4. 注册元数据

SpringBoot 源码解析7:Bean的创建② AbstractAutowireCapableBeanFactory#createBean

在doCreateBean方法源码中,我们可以知道,在实例化bean之后,会通过applyMergedBeanDefinitionPostProcessors方法回调MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition。

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof MergedBeanDefinitionPostProcessor) {
			MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
			bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}
}

AutowiredAnnotationBeanPostProcessor继承了MergedBeanDefinitionPostProcessor
在这里插入图片描述
元数据的注册的核心逻辑就在AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

4.1 AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
	metadata.checkConfigMembers(beanDefinition);
}

通过findAutowiringMetadata方法找到需要注入的元数据,然后还会检查一下成员变量。
暂时不知道checkConfigMembers的作用。

4.2 AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	// Fall back to class name as cache key, for backwards compatibility with custom callers.
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// Quick check on the concurrent map first, with minimal locking.
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	if (InjectionMetadata.needsRefresh(metadata, clazz)) {
		synchronized (this.injectionMetadataCache) {
			metadata = this.injectionMetadataCache.get(cacheKey);
			if (InjectionMetadata.needsRefresh(metadata, clazz)) {
				if (metadata != null) {
					metadata.clear(pvs);
				}
				metadata = buildAutowiringMetadata(clazz);
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
	return metadata;
}
  1. 做了一个缓存injectionMetadataCache,将注入信息的流程与注入流程分开,注入时直接从缓存中获取信息。
  2. pvs为已经注入的属性,metadata.clear(pvs)会清除掉这些信息,不会重复注入。

4.3 AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata


private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);

private String requiredParameterName = "required";

public AutowiredAnnotationBeanPostProcessor() {
	this.autowiredAnnotationTypes.add(Autowired.class);
	this.autowiredAnnotationTypes.add(Value.class);
	try {
		this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
				ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
		logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
	if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
		return InjectionMetadata.EMPTY;
	}

	List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
	Class<?> targetClass = clazz;

	do {
		final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
		// 1. 先扫描方法上面的注入注解
		ReflectionUtils.doWithLocalFields(targetClass, field -> {
			MergedAnnotation<?> ann = findAutowiredAnnotation(field);
			if (ann != null) {
				// 不支持静态字段
				if (Modifier.isStatic(field.getModifiers())) {
					if (logger.isInfoEnabled()) {
						logger.info("Autowired annotation is not supported on static fields: " + field);
					}
					return;
				}
				// 是否必须注入,默认为true,找不到bean就会抛出异常
				boolean required = determineRequiredStatus(ann);
				// 注册
				currElements.add(new AutowiredFieldElement(field, required));
			}
		});
		
		// 2. 再扫描方法上面的注入注解
		ReflectionUtils.doWithLocalMethods(targetClass, method -> {
			// 通过桥接方法找到原始的方法
			Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
			if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
				return;
			}
			// 判断方法上面是否有注入注解
			MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
			// 获取到具体的方法,此时的方法可能是父类中的方法,但已被子类复写
			if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
				if (Modifier.isStatic(method.getModifiers())) {
					if (logger.isInfoEnabled()) {
						logger.info("Autowired annotation is not supported on static methods: " + method);
					}
					return;
				}
				if (method.getParameterCount() == 0) {
					if (logger.isInfoEnabled()) {
						logger.info("Autowired annotation should only be used on methods with parameters: " +
								method);
					}
				}
				// 判断是否必须注入
				boolean required = determineRequiredStatus(ann);
				PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
				//注册
				currElements.add(new AutowiredMethodElement(method, required, pd));
			}
		});
		// 优先是否方法注入
		elements.addAll(0, currElements);
		targetClass = targetClass.getSuperclass();
	}
	while (targetClass != null && targetClass != Object.class);

	return InjectionMetadata.forElements(elements, clazz);
}

这是获取需要注入的元数据的核心方法

  1. 支持的注入注解包含Autowired、Value、Inject。
  2. 不支持静态注入,因为静态属于类的信息。
  3. 将方法注入的元数据放入到前面,所以方法先注入,后面字段注入会覆盖方法注入。
  4. 字段注入创建的是AutowiredFieldElement, 方法注入创建的是AutowiredMethodElement。字段注入和方法注入的逻辑基本一样的,后面讲解以demo中的字段注入为例。
  5. 最终,将要注入的信息封装到InjectionMetadata,完成注入信息的注册。
public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
	return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
}

5. 字段注入逻辑

AbstractAutowireCapableBeanFactory#populateBean方法负责对bean的属性的初始化。回调了InstantiationAwareBeanPostProcessor#postProcessProperties。

PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
	if (pvs == null) {
		pvs = mbd.getPropertyValues();
	}
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			if (pvsToUse == null) {
				if (filteredPds == null) {
					filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
				}
				pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					return;
				}
			}
			pvs = pvsToUse;
		}
	}
}

每次调用postProcessProperties会传入PropertyValues

5.1 AutowiredAnnotationBeanPostProcessor#postProcessProperties

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

第二次调用findAutowiringMetadata从缓存中获取要注入的元素信息,并且将已经注入成功的pvs删除掉。

5.2 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Field field = (Field) this.member;
	Object value;
	if (this.cached) {
		value = resolvedCachedArgument(beanName, this.cachedFieldValue);
	}
	else {
		// 将字段和是否强制注入封装城描述信息
		DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
		desc.setContainingClass(bean.getClass());
		Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
		Assert.state(beanFactory != null, "No BeanFactory available");
		// 获取类型转换器
		TypeConverter typeConverter = beanFactory.getTypeConverter();
		try {
			// 创建依赖的bean,也就是字段所对应的bean
			value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
		}
		catch (BeansException ex) {
			// 创建bean依赖的bean失败
			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
		}
		synchronized (this) {
			// 如果没有添加缓存,那么就会添加缓存
			if (!this.cached) {
				if (value != null || this.required) {
					this.cachedFieldValue = desc;
					// 注册bean的依赖关系
					registerDependentBeans(beanName, autowiredBeanNames);
					if (autowiredBeanNames.size() == 1) {
						String autowiredBeanName = autowiredBeanNames.iterator().next();
						if (beanFactory.containsBean(autowiredBeanName) &&
								beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
							this.cachedFieldValue = new ShortcutDependencyDescriptor(
									desc, autowiredBeanName, field.getType());
						}
					}
				}
				else {
					this.cachedFieldValue = null;
				}
				this.cached = true;
			}
		}
	}
	// 设置属性的值
	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}
  1. 这是@Autowired注解字段注入的实现逻辑。将依赖的bean的描述信息封装在DependencyDescriptor 中,通过beanFactory.resolveDependency解决依赖,方法的返回值就是所依赖的bean。
  2. cached:缓存了bean的依赖信息。
  3. 最终通过反射,完成了字段的初始化。

总结:beanFactory.resolveDependency方法获取到依赖的bean,通过反射field.set(bean, value)对字段赋值。

5.3 解决依赖关系 DefaultListableBeanFactory#doResolveDependency

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
	try {
		Object shortcut = descriptor.resolveShortcut(this);
		if (shortcut != null) {
			return shortcut;
		}

		Class<?> type = descriptor.getDependencyType();
		// 对@Value注解进行解析,返回的是value值
		Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
		if (value != null) {
			if (value instanceof String) {
				String strVal = resolveEmbeddedValue((String) value);
				BeanDefinition bd = (beanName != null && containsBean(beanName) ?
						getMergedBeanDefinition(beanName) : null);
				value = evaluateBeanDefinitionString(strVal, bd);
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			try {
				return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
			}
			catch (UnsupportedOperationException ex) {
				// A custom TypeConverter which does not support TypeDescriptor resolution...
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}
		}
		
		// 这里是对集合、数组、Map注入的支持
		Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
		if (multipleBeans != null) {
			return multipleBeans;
		}

		// 返回所有匹配的信息
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		if (matchingBeans.isEmpty()) {
			if (isRequired(descriptor)) {
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			return null;
		}

		String autowiredBeanName;
		Object instanceCandidate;

		if (matchingBeans.size() > 1) {
			// 如果根据type匹配多个,那么就解析@Primary或者Order匹配
			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			if (autowiredBeanName == null) {
				if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
					return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
				}
				else {
					// In case of an optional Collection/Map, silently ignore a non-unique case:
					// possibly it was meant to be an empty collection of multiple regular beans
					// (before 4.3 in particular when we didn't even look for collection beans).
					return null;
				}
			}
			instanceCandidate = matchingBeans.get(autowiredBeanName);
		}
		else {
			// We have exactly one match.
			// By Type只能匹配到一个
			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
			autowiredBeanName = entry.getKey();
			instanceCandidate = entry.getValue();
		}

		if (autowiredBeanNames != null) {
			autowiredBeanNames.add(autowiredBeanName);
		}
		if (instanceCandidate instanceof Class) {
			// 这里By name取bean实例
			instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
		}
		Object result = instanceCandidate;
		if (result instanceof NullBean) {
			// 校验bean是否与类型匹配
			if (isRequired(descriptor)) {
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			result = null;
		}
		if (!ClassUtils.isAssignableValue(type, result)) {
			throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
		}
		return result;
	}
	finally {
		ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
	}
}
  1. getAutowireCandidateResolver().getSuggestedValue():对@Value注解注入的支持。
  2. resolveMultipleBeans:对数组、集合、Map注入的支持。
  3. findAutowireCandidates:返回所有匹配的信息,返回一个map,key为beanName,如果依赖bean创建完毕,value就为依赖bean,否则就是beanClass。
    为什么说@Autowired注解是By Type注入的呢?原因就在DefaultListableBeanFactory#findAutowireCandidates这个方法!
    在这里插入图片描述BeanFactoryUtils.beanNamesForTypeIncludingAncestors通过给定的类型,找到所有的对应的beanName,然后在通过beanName去获取Bean。
    不要将@Autowired注入方式简简单单的理解为 通过类型直接匹配bean。在Spring中,不管是bean的注册(保存在beanDefinitionMap中,key为beanName)还是单例bean的保存(singletonObjects,key为beanName),他们的身份标识都为beanName,就算用户没有指定beanName,Spring中内置了BeanNameGenerator自动生成bean的名称。
  4. 如果有多个匹配的bean,那么就通过determineAutowireCandidate取最合适的那个,由@Primary注解和@Order决定。
  5. 上述说过,By Type匹配的时候,依赖bean还没有创建成功,返回的就是type,那么就会通过descriptor.resolveCandidate创建真正的bean。创建bean毫无疑问就要调用beanFactory.getBean。
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
		throws BeansException {

	return beanFactory.getBean(beanName);
}
  1. 这个方法的本身就是By Type注入。如果需要By Name 注入,就要调用AbstractAutowireCapableBeanFactory#resolveBeanByName。

5.4 Autowired注入逻辑总结

核心方法是doResolveDependency。首先是By Type取出所有的beanName,然后通过beanName从beanFactory取出bean,最后设置属性中。

6. @Resource注入方式

读了上述内容,我们知道了注入方法。那么,@Resource的注入方式是什么呢?
那么就要看CommonAnnotationBeanPostProcessor源码了。

6.1 Demo

@Component
public class ResourceA {
    @Resource
    private ResourceB resourceB;
}

@Component
public class ResourceB {
}

字段注册和Autowired逻辑基本一致

6.2 Resource注入逻辑

调用链:

  1. CommonAnnotationBeanPostProcessor#postProcessProperties
  2. InjectedElement#inject
  3. CommonAnnotationBeanPostProcessor.ResourceElement#getResourceToInject
  4. CommonAnnotationBeanPostProcessor#getResource
  5. CommonAnnotationBeanPostProcessor#autowireResource

6.3 CommonAnnotationBeanPostProcessor#autowireResource

protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
		throws NoSuchBeanDefinitionException {

	Object resource;
	Set<String> autowiredBeanNames;
	String name = element.name;

	if (factory instanceof AutowireCapableBeanFactory) {
		AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
		DependencyDescriptor descriptor = element.getDependencyDescriptor();
		// 判断为True,就需要By Type的方式解决依赖
		if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
			autowiredBeanNames = new LinkedHashSet<>();
			resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
			if (resource == null) {
				throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
			}
		}
		else {
			// 这里是By Name的方式解决依赖
			resource = beanFactory.resolveBeanByName(name, descriptor);
			autowiredBeanNames = Collections.singleton(name);
		}
	}
	else {
		resource = factory.getBean(name, element.lookupType);
		autowiredBeanNames = Collections.singleton(name);
	}

	if (factory instanceof ConfigurableBeanFactory) {
		ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
		for (String autowiredBeanName : autowiredBeanNames) {
			if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
				beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
			}
		}
	}

	return resource;
}
  1. 判断条件
    条件一:fallbackToDefaultTypeMatch默认为true。
    在这里插入图片描述
    条件二:是否使用默认名称。如果用户指定了依赖的bean的名称,那么就认为指定的bean必然要存在,isDefaultName就为false,就需要By Name取获取依赖bean。否则就使用字段的名称。
    在这里插入图片描述

    条件三:beanName没有对应的实例或者beanDefinition。如果没有,那么就By Type去解决依赖关系。为什么这样呢?比如应该是

@Override
public boolean containsBean(String name) {
	String beanName = transformedBeanName(name);
	if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
		return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
	}
	// Not found -> check parent.
	BeanFactory parentBeanFactory = getParentBeanFactory();
	return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
}
  1. 只有满足同时上述三个条件才会By Type获取bean。所以也兼容 By Type注入。
  2. 为什么要有条件三呢?
    因为ResourceB对应的bean被默认的BeanNamegenerator生成的beanName为"resourceB"。兼容了即使用户写错了变量名称,也要注入成功。比如:
@Resource
private ResourceB b;

6.4 结论

所以,@Resource注入逻辑如下:

  1. 如果用户指定了beanName,那么就通过beanName注入。
  2. 如果用户没有指定beanName,注入的字段名称存在对应的bean,那么就By Name注入。如果不存在对应的bean就是 By Type注入。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1511644.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【NR 定位】3GPP NR Positioning 5G定位标准解读(十二)-Multi-RTT定位

前言 3GPP NR Positioning 5G定位标准&#xff1a;3GPP TS 38.305 V18 3GPP 标准网址&#xff1a;Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;一&#xff09;-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;…

Hive面经

hive原理 Hive 内部表和外部表的区别Hive 有索引吗运维如何对 Hive 进行调度ORC、Parquet 等列式存储的优点数据建模用的哪些模型&#xff1f;1. 星型模型2. 雪花模型3. 星座模型 为什么要对数据仓库分层&#xff1f;使用过 Hive 解析 JSON 串吗sort by 和 order by 的区别数据…

React 教程

学习主要来源 React 教程 | 菜鸟教程 React 是一个用于构建用户界面的 JAVASCRIPT 库。 React 主要用于构建 UI&#xff0c;很多人认为 React 是 MVC 中的 V&#xff08;视图&#xff09;。 React 起源于 Facebook 的内部项目&#xff0c;用来架设 Instagram 的网站&#xff0…

GSEA -- 学习记录

文章目录 brief统计学原理部分其他注意事项转录组部分单细胞部分 brief 上一篇学习记录写了ORA&#xff0c;其中ORA方法只关心差异表达基因而不关心其上调、下调的方向&#xff0c;也许同一条通路里既有显著高表达的基因&#xff0c;也有显著低表达的基因&#xff0c;因此最后…

2023年第三届中国高校大数据挑战赛第二场赛题C:用户对博物馆评论的情感分析(附上代码与详细视频讲解)

问题重述&#xff1a; 博物馆是公共文化服务体系的重要组成部分。国家文物局发布&#xff0c; 2021 年我国新增备案博物馆 395 家&#xff0c;备案博物馆总数达 6183 家&#xff0c;排名全球前列&#xff1b;5605 家博物馆实现免费开放&#xff0c;占比达 90%以上&#xff1b;…

基于Springboot的高校汉服租赁网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的高校汉服租赁网站&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

蓝桥杯算法错题记录-基础篇

文章目录 本文还在跟新&#xff0c;最新跟新时间3/11&#xff01;&#xff01;&#xff01; 格式一定要符合要求&#xff0c;&#xff08;输入&#xff0c;输出格式&#xff09;1. nextInt () next() nextLine() 的注意事项2 .数的幂 a^2等3.得到最大长度&#xff08;最大...&a…

Redis缓存问题详解和处理

缓存更新策略 缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库. 常见的解决方案: 缓存空对象 优点: 实现简单, 维护方便缺点: 额外的内存消耗, 可能造成短期的不一致 布隆过滤 优点: 内存占用较少(保存的是数据…

【0基础学C语言】04-常量、变量

一、数据的存储 1.数据类型 首先来看看计算机是怎么存储数据的。总的来说,计算机中存储的数据可以分为两种:静态数据和动态数据。 1> 静态数据 概念:静态数据是指一些永久性的数据,一般存储在硬盘中。硬盘的存储空间一般都比较大,现在普通计算机的硬盘都有500G左右…

Leetcode每日一题[C++]-1261.在受污染的二叉树中查找元素

题目描述 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给出一个满足下述规则的二叉树&#xff1a; root.val 0如果 treeNode.val x 且 treeNode.left ! null&#xff0c;那么 treeNode.left.val 2 * x 1如果 treeNode.val x 且 treeNode.right ! nu…

这些年背过的面试题——SpringMVC篇

1 什么是SpringMVC &#xff1f;简单介绍下你对SpringMVC的理解? SpringMVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将web层进行职责解耦&#xff0c;把复杂的web应用…

ST MotorControl Workbench 6.2.1 使用总结

目录 前言 软件安装 根据自己硬件配置参数 生成代码 开发板运行 ​ 总结 前言 好久没有玩ST的电机库了&#xff0c;已经更新到了MotorControl Workbench 6.2.1&#xff0c;6以上的版本比5的版本界面操作有很大的不同&#xff0c;核心算法有些增加。最近体验了一把使用自…

jeecg 启动 微服务 更改配置本地host地址

1. windows系统下&#xff0c;在开始—运行里面输入(找不到运行菜单可直接按WinR键)&#xff1a; C:\WINDOWS\system32\drivers\etc &#xff0c;如图所示&#xff1a; 2. 用记事本 打开这个文件 在最下面输入这个即可

G. Rudolf and Subway

解题思路 每条边的边权可选&#xff0c;由颜色决定同一颜色的线路可以直达颜色最多有种考虑将颜色视作链接点&#xff0c;进行分层图跑最短路最终结果除2最多建条边&#xff08;直接存状态Map跑最短路被毙掉了&#xff09; import java.io.*; import java.math.BigInteger; im…

【案例】IPC 中的WinCC RT Advanced PC项目,如何下载及开机自动启动?

导读&#xff1a;TIA WinCC Advanced (高级版)V17项目如何下载到目标计算机&#xff08;需要运行项目的电脑&#xff09;&#xff1f; 01WinCC RT Adv项目下载 1、在计算机开始菜单中点击“运行”或通过Win键R调出运行窗口&#xff0c;并输入 CMD 然后回车&#xff1a; 打开 W…

虚拟化

什么是虚拟化 虚拟化&#xff08;Virtualization&#xff09;是一种资源分配和管理技术&#xff0c;是将计算机的各种实体资源,比如CPU、内存、磁盘空间、网络适配器等&#xff0c;进行抽象转换后虚拟的设备,可以实现灵活地分割、组合为一个或多个计算机配置环境&#xff0c;并…

rt-thread组件之audio组件(结合mp3player包使用)

前言 继上一篇RT-Thread组件之Audio框架i2s驱动的编写的编写&#xff0c;应用层使用rt-thread软件包里面的wavplayer组件以及 rt-thread组件之audio组件(结合wavplayer包使用)的文章本篇使用的是 mp3player软件包&#xff0c;与wavplayer设计框架基本上是一样的&#xff0c;只…

万字完整版【C语言】指针详解~

一、前言 初始指针&#xff08;0&#xff09;&#xff1a;着重于讲解指针的概念、基本用法、注意事项、以及最后如何规范使用指针深入指针&#xff08;1&#xff09;&#xff1a;讲解指针变量常见的类型&#xff0c;如何去理解这些类型、最后就是如何正确的使用深入指针&#…

语音情感基座模型emotion2vec

在语音技术领域&#xff0c;准确理解用户的语音指令和意图是构建高效人机交互系统的基础。一个高品质的语音交互系统不仅需要理解字面上的语言内容&#xff0c;更应捕捉到说话者语音中蕴含的情感信息。这正是语音情感识别&#xff08;SER&#xff09;技术要解决的问题&#xff…

【libwebrtc】基于m114的构建

libwebrtc A C++ wrapper for binary release, mainly used for flutter-webrtc desktop (windows, linux, embedded).是 基于m114版本的webrtc 最新(20240309 ) 的是m122了。官方给出的构建过程 .gclient 文件 solutions = [{"name" : src,"url