## spring-@Autowired实现

spring-@Autowired实现

我们知道 spring 中有很多的后置处理器 BeanPostProcessor, 而 @Autowired 就是通过 AutowiredAnnotationBeanPostProcessor 来实现的

与之相似的还有 CommonAnnotationBeanPostProcessor 处理 @Resource 注解

AutowiredAnnotationBeanPostProcessor

构造函数

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.}
}

可以看出 AutowiredAnnotationBeanPostProcessor 同时处理 @Autowird和@Value 的解析

主要看 AutowiredAnnotationBeanPostProcessor#postProcessProperties 方法, postProcessPropertyValues 这个方法被遗弃了

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//找到有autowired 和 value的属性或者方法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;
}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;
}//通过反射获取类字段和带有autowired的注解
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}final List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;do {final List<InjectionMetadata.InjectedElement> fieldElements = new ArrayList<>();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;}boolean required = determineRequiredStatus(ann);fieldElements.add(new AutowiredFieldElement(field, required));}});final List<InjectionMetadata.InjectedElement> methodElements = new ArrayList<>();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);methodElements.add(new AutowiredMethodElement(method, required, pd));}});elements.addAll(0, sortMethodElements(methodElements, targetClass));elements.addAll(0, fieldElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);
}

注意,这里加入的是 AutowiredFieldElementAutowiredMethodElement

通过InjectionMetadata#inject方法注入


public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {for (InjectedElement element : elementsToIterate) {element.inject(target, beanName, pvs);}}
}

这里就要看 InjectedElement 的实现类了,以刚才 AutowiredFieldElement 为例

private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {private final boolean required;private volatile boolean cached;@Nullableprivate volatile Object cachedFieldValue;public AutowiredFieldElement(Field field, boolean required) {super(field, null);this.required = required;}@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;if (this.cached) {try {value = resolveCachedArgument(beanName, this.cachedFieldValue);}catch (BeansException ex) {// Unexpected target bean mismatch for cached argument -> re-resolvethis.cached = false;logger.debug("Failed to resolve cached argument", ex);value = resolveFieldValue(field, bean, beanName);}}else {value = resolveFieldValue(field, bean, beanName);}if (value != null) {ReflectionUtils.makeAccessible(field);field.set(bean, value);}}@Nullableprivate Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {DependencyDescriptor desc = new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());Set<String> autowiredBeanNames = new LinkedHashSet<>(2);Assert.state(beanFactory != null, "No BeanFactory available");TypeConverter typeConverter = beanFactory.getTypeConverter();Object value;try {value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);}catch (BeansException ex) {throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);}synchronized (this) {if (!this.cached) {if (value != null || this.required) {Object cachedFieldValue = desc;registerDependentBeans(beanName, autowiredBeanNames);if (value != null && autowiredBeanNames.size() == 1) {String autowiredBeanName = autowiredBeanNames.iterator().next();if (beanFactory.containsBean(autowiredBeanName) &&beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName);}}this.cachedFieldValue = cachedFieldValue;this.cached = true;}else {this.cachedFieldValue = null;// cached flag remains false}}}return value;}
}

继续跟进 beanFactory.resolveDependency 方法 ,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();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()));}}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) {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.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) {instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);}Object result = instanceCandidate;if (result instanceof NullBean) {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);}
}

再看 value instanceof String里面的 resolveEmbeddedValue 方法,这个就是处理 @Value处理的逻辑

public String resolveEmbeddedValue(@Nullable String value) {if (value == null) {return null;}String result = value;for (StringValueResolver resolver : this.embeddedValueResolvers) {result = resolver.resolveStringValue(result);if (result == null) {return null;}}return result;
}

最后交给了 StringValueResolver 去处理

  • PropertyPlaceholderConfigurerResolver: 处理占位符
  • StaticStringValueResolver: 处理静态变量
private class PlaceholderResolvingStringValueResolver implements StringValueResolver {private final PropertyPlaceholderHelper helper;private final PlaceholderResolver resolver;public PlaceholderResolvingStringValueResolver(Properties props) {this.helper = new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);this.resolver = new PropertyPlaceholderConfigurerResolver(props);}@Override@Nullablepublic String resolveStringValue(String strVal) throws BeansException {String resolved = this.helper.replacePlaceholders(strVal, this.resolver);if (trimValues) {resolved = resolved.trim();}return (resolved.equals(nullValue) ? null : resolved);}
}

最终都交给 PropertyPlaceholderHelper#replacePlaceholders方法处理

现在回过头看下是在哪里调用了AutowiredAnnotationBeanPostProcessor#ostProcessProperties,不难发现,是在我们对bean初始化的时候,具体是在AbstractAutowiredCapableBeanFactory#populateBean 方法上:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {if (bw == null) {if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");}else {// Skip property population phase for null instance.return;}}// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the// state of the bean before properties are set. This can be used, for example,// to support styles of field injection.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);int resolvedAutowireMode = mbd.getResolvedAutowireMode();if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {//这里就是AutowiredAnnotationBeanPostProcessor入口PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}checkDependencies(beanName, mbd, filteredPds, pvs);}if (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs);}
}

因为 AutowiredAnnotationBeanPostProcessor 也是 InstantiationAwareBeanPostProcessor 子类

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

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

相关文章

java设计模式学习之【原型模式】

文章目录 引言原型模式简介定义与用途实现方式UML 使用场景优势与劣势原型模式在spring中的应用员工记录示例代码地址 引言 原型模式是一种创建型设计模式&#xff0c;它允许对象能够复制自身&#xff0c;以此来创建一个新的对象。这种模式在需要重复地创建相似对象时非常有用…

【代码】基于卷积神经网络(CNN)-支持向量机(SVM)的分类预测算法

程序名称&#xff1a;基于卷积神经网络&#xff08;CNN&#xff09;-支持向量机&#xff08;SVM&#xff09;的分类预测算法 实现平台&#xff1a;matlab 代码简介&#xff1a;CNN-SVM是一种常用的图像分类方法&#xff0c;结合了卷积神经网络&#xff08;CNN&#xff09;和支…

移动应用开发介绍及iOS方向学习路线(HUT移动组版)

移动应用开发介绍及iOS方向学习路线&#xff08;HUT移动组版&#xff09; 前言 ​ 作为一个HUT移动组待了一坤年&#xff08;两年半&#xff09;多的老人&#xff0c;在这里为还在考虑进哪个组的萌新们以及将来进组的新朋友提供一份关于移动应用开发介绍以及学习路线的白话文…

DC电源模块有哪些常见故障?怎么解决这些问题?

DC-DC电源模块的作用是将输入电压转换为所需的输出电压&#xff0c;广泛应用于电子产品、汽车电子、医疗设备、通信系统等领域。但是在使用过程中DC电源模块会出现一些故障和问题&#xff0c;影响电源模块和其它电路器件的性能。因此&#xff0c;纳米软件将为大家介绍常见的DC-…

大坝安全监测的内容及作用

大坝安全监测是指对大坝水雨情沉降、倾斜、渗压以及大坝形状特征有效地进行监测&#xff0c;及时发现潜在的安全隐患和异常情况&#xff0c;以便大坝管理人员能够做出科学决策&#xff0c;以确保大坝安全稳定运行。 大坝安全监测的主要内容 1.表面位移监测&#xff1a;监测大坝…

分子骨架跃迁工具-DiffHopp 评测

一、文章背景介绍 DiffHopp模型发表在ICML 2023 Workshop on Computational Biology&#xff08;简称&#xff1a;2023 ICML-WCB&#xff09;上的文章。第一作者是剑桥计算机系的Jos Torge。 DiffHopp是一个专门针对骨架跃迁任务而训练的E3等变条件扩散模型。此外&#xff0c;…

LeetCode Hot100 84.柱状图中最大的矩形

题目&#xff1a; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 方法&#xff1a; 代码&#xff1a; class Solution {public int largestRectang…

MySOL常见四种连接查询

1、内联接 &#xff08;典型的联接运算&#xff0c;使用像 或 <> 之类的比较运算符&#xff09;。包括相等联接和自然联接。 内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行。例如&#xff0c;检索 students和courses表中学生标识号相同的所有行。 2、…

机器学习之危险品车辆目标检测

危险品的运输涉及从离开仓库到由车辆运输到目的地的风险。监控事故、车辆运动动态以及车辆通过特定区域的频率对于监督车辆运输危险品的过程至关重要。 在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数…

使用STM32微控制器实现光电传感器的接口和数据处理

光电传感器在许多领域中被广泛应用&#xff0c;例如工业自动化、智能家居等。本文将介绍如何使用STM32微控制器实现光电传感器的接口和数据处理的方案&#xff0c;包括硬件设计、引脚配置、数据采集、滤波和阈值判断等关键步骤&#xff0c;并给出相应的代码示例。 一、引言 光…

MySQL使用函数和存储过程实现:向数据表快速插入大量测试数据

实现过程 1.创建表 CREATE TABLE user_info (id INT(11) NOT NULL AUTO_INCREMENT,name VARCHAR(20) DEFAULT NULL,age INT(3) DEFAULT NULL,pwd VARCHAR(20) DEFAULT NULL,phone_number VARCHAR(11) DEFAULT NULL,email VARCHAR(255) DEFAULT NULL,address VARCHAR(255) DEF…

DHCP协议及实验omnipeek抓包工具分析 IPv4协议

一 抓包命令 adb shell tcpdump -i wlan0 -w /data/tcpdump.pcap 抓包后截图如下 二 DHCP是什么 2.1 DHCP定义 DHCP( Dynamic Host Configuration Protocol, 动态主机配置协议)定义: 存在于应用层(OSI) 前身是BOOTP(Bootstrap Protocol)协议 是一个使用UDP(User …

如何编写自己的python包,并在本地进行使用

如何编写自己的python包,并在本地进行使用 一、直接引用 1.创建Python项目pythonProject。 2.并且在此项目下创建pg_message包。 3.pg_message包下默认生成_init_.py文件。 Python中_init_.py是package的标志。init.py 文件的一个主要作用是将文件夹变为一个Python模块,Pyt…

使用Jmeter进行http接口测试

前言&#xff1a; 本文主要针对http接口进行测试&#xff0c;使用Jmeter工具实现。 Jmter工具设计之初是用于做性能测试的&#xff0c;它在实现对各种接口的调用方面已经做的比较成熟&#xff0c;因此&#xff0c;本次直接使用Jmeter工具来完成对Http接口的测试。 一、开发接口…

杂记 | 使用Docker安装并配置MongoDB以支持事务(单副本,并解决了证书文件错误的问题)

文章目录 00 安装前的准备01 创建Docker Compose文件02 设置证书文件03 启动MongoDB04 初始化副本集和创建用户05 验证安装 00 安装前的准备 在开始之前&#xff0c;确保已经安装了Docker&#xff0c;本文基于Docker Compose进行示范&#xff0c;没有装Docker Compose也可将其…

人大金仓亮相2023信息技术应用创新论坛

11月25日&#xff0c;2023信息技术应用创新论坛在常州开幕。人大金仓受邀分享信息技术应用创新行业应用典型成果&#xff0c;在论坛展览部分集中展示了最具代表性的新产品、应用及解决方案。 江苏省工业和信息化厅副厅长池宇、中国电子工业标准化技术协会理事长胡燕、常州市常务…

量子力学技术前沿:探索、挑战与未来

量子力学技术前沿:探索、挑战与未来 一、引言 量子力学,这门揭示微观世界规律的学科,自诞生以来就在科技领域发挥着举足轻重的作用。随着科技的飞速发展,量子力学的应用也在不断拓展和深化。今天,我将带领大家一起领略量子力学技术的魅力,探讨其发展趋势和挑战。 二、量…

windows系统mobaxterm远程执行linux上ssh命令

命令如下 start "" "%~dp0\MobaXterm_Personal_23.4.exe" -newtab "sshpass -p root ssh root192.168.11.92 mkdir 33" -p 是密码 左边是用户名&#xff0c;右边是服务器ip 后面跟的是服务器上执行的命令 第一次执行的时候要设置mobaxt…

使用std::mutext与std::condition_variables实现信号量

1. 信号量的定义 2. 使用std::mutext与std::condition_variables实现信号量 代码来自&#xff1a;https://zhuanlan.zhihu.com/p/462668211 #ifndef _SEMAPHORE_H #define _SEMAPHORE_H #include <mutex> #include <condition_variable> using namespace std;cla…

ArrayList和顺序表

目录 线性表 顺序表 实现顺序表&#xff1a; 1&#xff0c;添加元素的时候我们要判断是否需要扩容 2&#xff0c;写异常 3,数组清空 ArrayList&#xff1a; ArrayList的构造方法&#xff1a; ArrayList的add方法&#xff1a; ArrayList的subList 知识点补充&#xff…