Spring源码:PropertyValues类及属性注入一

2023-11-17

概要

Spring获取Bean的实例时,需要把配置的属性值解析到PropertyValues,然后填充入BeanWrapper中

相关类

  • **MutablePropertyValues类:**PropertyValues接口的默认实现

    public class MutablePropertyValues implements PropertyValues, Serializable {
    
    private final List<PropertyValue> propertyValueList;
    
    private Set<String> processedProperties;
    
    private volatile boolean converted = false;
      //......
    }
  • PropertyValues接口:包含一个或多个PropertyValue对象的容器,通常包含特定目标bean的一个更新。

    public interface PropertyValues {
    
      PropertyValue[] getPropertyValues();
    
      PropertyValue getPropertyValue(String propertyName);
    
      PropertyValues changesSince(PropertyValues old);
    
      boolean contains(String propertyName);
    
      boolean isEmpty();
    }
  • PropertyValue类:保存单个bean属性的信息和值的对象

    public class PropertyValue extends BeanMetadataAttributeAccessor implements Serializable {
    
    private final String name;
    
    private final Object value;
    
    private boolean optional = false;
    
    private boolean converted = false;
    
    private Object convertedValue;
    
    /** Package-visible field that indicates whether conversion is necessary */
    volatile Boolean conversionNecessary;
    
    /** Package-visible field for caching the resolved property path tokens */
    transient volatile Object resolvedTokens;
    }
  • **BeanMetadataAttributeAccessor类:**AttributeAccessorSupport的扩展类

    public class BeanMetadataAttributeAccessor extends AttributeAccessorSupport implements BeanMetadataElement {
    
    private Object source;
      //......
    }
  • **AttributeAccessorSupport抽象类:**AttributeAccessor的基本实现类

    public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {
    
    private final Map<String, Object> attributes = new LinkedHashMap<String, Object>(0);
      //......
    }
  • AttributeAccessor接口

    public interface AttributeAccessor {
    void setAttribute(String name, Object value);
    
    Object getAttribute(String name);
    
    Object removeAttribute(String name);
    
    boolean hasAttribute(String name);
    
    String[] attributeNames();
    }

属性注入

Spring获取Bean的实例时,需要把配置的属性值解析到PropertyValues,然后填充入BeanWrapper中,注入函数在抽象类AbstractAutowireCapableBeanFactory中的applyPropertyValues方法中,详细分析如下:

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    // 若没有要注入的属性,直接返回
    if (pvs == null || pvs.isEmpty()) {
        return;
    }

    MutablePropertyValues mpvs = null;
    // 需要转换的属性
    List<PropertyValue> original;

    if (System.getSecurityManager() != null) {
        if (bw instanceof BeanWrapperImpl) {
            ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
        }
    }


    if (pvs instanceof MutablePropertyValues) {
        mpvs = (MutablePropertyValues) pvs;
        if (mpvs.isConverted()) {
            // 若该mpvs中的所有属性值都已经转换为对应的类型,则把mpvs设置到BeanWrapper中,返回
            bw.setPropertyValues(mpvs);
            return;
        }
        original = mpvs.getPropertyValueList();
    } else {
        original = Arrays.asList(pvs.getPropertyValues());
    }

    // 获取用户自定义类型转换器
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }
    //获取BeanDefinitionValueResolver,该Bean用于将bean定义对象中包含的值解析为应用于目标bean实例的实际值。
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
    // 用于存放实际解析后的属性集合
    List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
    boolean resolveNecessary = false;
    // 遍历未解析的属性
    for (PropertyValue pv : original) {
        if (pv.isConverted()) {
            // 若该属性已经解析过
            deepCopy.add(pv);
        } else {
            // 若该属性没有被解析过
            String propertyName = pv.getName(); // 属性名称
            Object originalValue = pv.getValue(); // 属性未经类型转换的值
            // 解析值
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
            Object convertedValue = resolvedValue;
            // 属性可写 && 不是嵌套(如foo.bar,java中用getFoo().getBar()表示)或者索引(如person.addresses[0])属性
            boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
            if (convertible) {
                // 用类型转换器进行转换
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }

           // 可能将转换后的值存储在merged bean definition中,避免对每个创建的bean实例进行重新转换。
            if (resolvedValue == originalValue) {
                if (convertible) {
                    pv.setConvertedValue(convertedValue);
                }
                deepCopy.add(pv);
            } else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue) originalValue).isDynamic() && !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                pv.setConvertedValue(convertedValue);
                deepCopy.add(pv);
            } else {
                resolveNecessary = true;
                deepCopy.add(new PropertyValue(pv, convertedValue));
            }
        }
    } // for

    if (mpvs != null && !resolveNecessary) {
        // 标记mpvs已经转换
        mpvs.setConverted();
    }
    // 构造MutablePropertyValues并填充到BeanWrapper中
    bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring源码:PropertyValues类及属性注入一 的相关文章

随机推荐

  • Python 进阶(七): Word 基本操作

    1 概述 Word 是一个十分常用的文字处理工具 通常我们都是手动来操作它 本节我们来看一下如何通过 Python 来操作 Python 提供了 python docx 库 该库就是为 Word 文档量身定制的 安装使用 pip insta
  • openwrt 格式化_如何在路由器上格式化 U 盘、硬盘

    本教程适用于梅林 padavan LEDE openwrt 等固件 以下具体方法都基于 ext4 NTFS 相关错误不做回答 使用ssh连接路由器 把U盘插到路由器上 我们需要在命令行进行以下4步操作 安装fdisk 一般梅林 Padava
  • Keil(MDK-ARM-STM32)系列教程(六)Configuration(Ⅱ)

    写在前面 本文接着上一篇文章 Configuration 进行讲述Configuration后面三项Shortcut Keys快捷键 Text Completion代码完形 Other其他的内容 Shortcut Keys快捷键 Keil软
  • 精学JS:宏任务 & 微任务的运行机制

    首先分析宏任务和微任务的运行机制 并针对日常开发中遇到的各种宏任务 微任务的方法 结合一些例子来看看代码运行的顺序逻辑 把这部分知识点重新归纳和梳理 在日常开发中 例如 setTimeout和 promise都是经常会使用到的 JS方法 当
  • 操作系统【六】虚拟内存

    传统存储管理方式的不足 一次性 作业必须一次性全部装入内存后才能开始运行 这会造成 当作也很大时不能全部装入内存 当大量作业要求运行时 由于内存无法容纳所有作业 因此只有少量作业能够运行 导致多道程序并发度下降 驻留性 一旦作业被装入内存
  • 【计算机视觉】Visual Transformer (ViT)模型结构以及原理解析

    文章目录 一 简介 二 Vision Transformer如何工作 三 ViT模型架构 四 ViT工作原理解析 4 1 步骤1 将图片转换成patches序列 4 2 步骤2 将patches铺平 4 3 步骤3 添加Position e
  • Python——LSTM、GRU 时间序列股票数据预测(文末完整代码)

    GRU 是在 LSTM 基础上的简化 将 LSTM 内部的三个闸门简化成两个 往往 GRU 的计算效果会优于 LSTM 目录 1 导入工具包 2 获取数据集 3 数据预处理 4 时间序列滑窗 5 数据集划分 6 构造网络模型 7 网络训练
  • tracert命令返回的三个时间为什么有时会出现1个或2个星号?

    如图 三个时间里有1个或者2个显示星号 这是为什么呢 如果是配置了ACL丢弃了响应报文的话按理应该3个都显示星号呀 直接ping这个ip的话不会出现丢包 时延也很稳定 这个问题很诡异 演绎一下 仅供参考 首先traceroute 是利用 T
  • 后台系统切换主题颜色(换肤) Vue+ elementUi

    文章目录 前言 一 css color function 二 使用步骤 1 下载依赖项 2 引入 3 使用 定义data数据 3 定义方法 4 调用方法使用 5 模板 6 AllCode 总结 前言 不断学习demo中 有好的demo会记录
  • antd pro protable request请求有数据 页面不渲染或postdata里的data一直是undefined

    异常原因 protable的request请求默认的数据格式为 data pageSize 10 current 1 total 28 success true request请求如果返回的数据格式不是以上形式就会获取不到data page
  • STM32 DMA 应用之(二) DMA 串口 数据传输--发送

    一 DMA请求映像 由此我们知道如果需要使用串口1的发送功能需要用到的是DMA1 Channel4 使用串口1的接收功能需要用到的是DMA1 Channel5 二 怎样配置软件来使用DMA 把数据传到串口发送 1 配置dma 函数名称 Dm
  • vim退出时提示:q:未找到命令的解决办法

    有一天 我在WSL上快乐的用vim编游戏 可就在我输入 q时 bash提醒我 q 未找到命令 平常程序都在WSL上 cat不自动在行尾加换行违反了我的强迫症 然后我就开始修理vim了 然后我又试了 wq等等和q有关的命令 甚至连 q都没问题
  • C#编程,.NTE调用java类、jar包方法

    基本思路 用C 实现调用Java编写的类中的方法 重点是将Java编写的程序打包成Jar 然后使用开源工具IKVM将其转化成DLL控件 在 NET环境下调用 一 使用IKVM NET组件 首先到IKVM官网 http www ikvm ne
  • React学习(JSX+组件+state+表单)

    React JSX 声明元素 渲染元素 组件 练习 this props children PropTypes 默认值 获取真实的DOM节点 this state 表单 组件的生命周期 例子 JSX JSX是一种JavaScript语法的拓
  • 链式前向星存树图和遍历它的两种方法【dfs、bfs】

    目录 一 链式前向星存图 二 两种遍历方法 一 链式前向星存图 n个点 n 1条边 链式前向星把上面的树图存下来 输入 9 代表要存进去n个点 1 2 下面是n 1条边 每条边连接两个点 1 3 1 7 2 4 4 5 4 6 3 8 3
  • json-server在vscode终端运行文件报错

    错误 无法加载文件 D 因为在此系统上禁止运行脚本 json server 无法加载文件 D ruanjian nodejs node global json server ps1 因为在此系 统上禁止运行脚本 有关详细信息 请参阅 htt
  • 关于宝塔面板无法访问的解决方法

    前言 本篇文章主要介绍宝塔面板无法访问的几种情况以及如何解决 正文 1 没有开放相应端口 这种情况比较常见 服务商默认情况下会将所有的端口关闭 你需要使用哪个端口就得手动去打开这个端口 例如 http 47 8888 adminuser 中
  • ubuntu如何开放22端口 ubuntu22端口开启

    ubuntu开放22端口的操作步骤 1 打开终端命令行模式 2 依次输入以下命令进行开放22端口即可 输入以下命令打开22端口 sudo ufw allow 22 重启防火墙使其生效即可 sudo ufw reload 附加 sudo ap
  • 详解混合类型文件(Polyglot文件)的应用生成与检测

    1 引入 混合类型文件 Polyglot文件 是指一个文件 既可以是合法的A类型 也可以是合法的B类型 比如参考3中的文件 是一个html文件 可以用浏览器正常打开 它也是一个一个 jar文件 可以用JVM正常运行 参考4 如下图所示 这样
  • Spring源码:PropertyValues类及属性注入一

    概要 相关类 属性注入 概要 Spring获取Bean的实例时 需要把配置的属性值解析到PropertyValues 然后填充入BeanWrapper中 相关类 MutablePropertyValues类 PropertyValues接口