[Spring 从模拟开始学习源码]`@Value`的底层实现

@Value 注入主要有三种场景:

  1. 注入原始值,比如说注入Value("hello")
  2. 注入变量,比如@Value("${JAVA_HOME}")
  3. 注入spel表达式,比如@Value("#{1 + 2}")

文章目录

    • 获取 `@Value`内容
    • 解析 `${}`内容
    • 解析 `SPEL`
    • 类型转换

package com.example.value;import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;@Configuration // 自动扫描bean3
public class ValueApplication {public static void main(String[] args) throws Exception {AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(ValueApplication.class);DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();ContextAnnotationAutowireCandidateResolver resolver =new ContextAnnotationAutowireCandidateResolver();resolver.setBeanFactory(beanFactory);test1(context, resolver);test2(context, resolver);test3(context, resolver, Bean2.class.getDeclaredField("bean3"));System.out.println(">>>>>>>>>>>>>>>>>>>");test3(context, resolver, Bean4.class.getDeclaredField("value"));}private static void test1(AnnotationConfigApplicationContext context,ContextAnnotationAutowireCandidateResolver resolver) throws Exception {DependencyDescriptor dd1 =new DependencyDescriptor(Bean1.class.getDeclaredField("home"), false);// 获取 @Value 的内容String value = resolver.getSuggestedValue(dd1).toString();System.out.println(value);// 解析 ${}value = context.getEnvironment().resolvePlaceholders(value);System.out.println(value);}// ${} -> 类型private static void test2(AnnotationConfigApplicationContext context,ContextAnnotationAutowireCandidateResolver resolver) throws Exception{DependencyDescriptor dd1 =new DependencyDescriptor(Bean1.class.getDeclaredField("age"), false);// 获取 @Value 的内容String value = resolver.getSuggestedValue(dd1).toString();System.out.println("@Value 的 value 属性值: " + value);// 解析 ${}value = context.getEnvironment().resolvePlaceholders(value);System.out.println("解析得到的值: " + value);System.out.println("解析得到的值的类型: " + value.getClass());// 转成字段的类型Object age = context.getBeanFactory().getTypeConverter().convertIfNecessary(value, dd1.getDependencyType());System.out.println("转换后的类型: " + age.getClass());}// spelprivate static void test3(AnnotationConfigApplicationContext context,ContextAnnotationAutowireCandidateResolver resolver,Field field) throws Exception {DependencyDescriptor dd1 = new DependencyDescriptor(field, false);// 获取 @Value 的内容String value = resolver.getSuggestedValue(dd1).toString();System.out.println("@Value 的 value 属性值: " + value);// 解析 ${}value = context.getEnvironment().resolvePlaceholders(value);System.out.println("解析得到的值: " + value);System.out.println("解析得到的值的类型: " + value.getClass());// 解析 #{}Object bean3 = context.getBeanFactory().getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));// 类型转换Object result = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3, dd1.getDependencyType());System.out.println("转换后的类型: " + result.getClass());}static class Bean1 {@Value("${JAVA_HOME}")private String home;@Value("18")private int age;}static class Bean2 {@Value("#{@bean3}")private Bean3 bean3;}@Component("bean3")static class Bean3 {}static class Bean4 {@Value("#{'hello, ' + '${JAVA_HOME}'}")private String value;}}

输出结果

${JAVA_HOME}
/Users/xx/Library/Java/JavaVirtualMachines/corretto-17.0.8.1/Contents/Home
@Value 的 value 属性值: 18
解析得到的值: 18
解析得到的值的类型: class java.lang.String
转换后的类型: class java.lang.Integer
@Value 的 value 属性值: #{@bean3}
解析得到的值: #{@bean3}
解析得到的值的类型: class java.lang.String
转换后的类型: class com.example.value.ValueApplication$Bean3
>>>>>>>>>>>>>>>>>>>
@Value 的 value 属性值: #{'hello, ' + '${JAVA_HOME}'}
解析得到的值: #{'hello, ' + '/Users/xx/Library/Java/JavaVirtualMachines/corretto-17.0.8.1/Contents/Home'}
解析得到的值的类型: class java.lang.String
转换后的类型: class java.lang.String

用到的几个工具类

获取 @Value内容

Bean2.class.getDeclaredField("bean3")
DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
// 获取 @Value 的内容
String value = resolver.getSuggestedValue(dd1).toString();

解析 ${}内容

value = context.getEnvironment().resolvePlaceholders(value);

解析 SPEL

Object bean3 = context.getBeanFactory().getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));

类型转换

Object result = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3, dd1.getDependencyType());

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

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

相关文章

云计算:Vmware 安装 FreeNAS

目录 一、实验 1.Vmware 安装 FreeNAS 2.配置Web界面 二、问题 1.iSCSI如何限定名称 2.LUN和LVM的区别 一、实验 1.Vmware 安装 FreeNAS (1)环境准备 VMware Workstation 17 FreeNAS相关安装部署镜像: 官网地址: https://download…

【linux】SSH终端Putty配置:文件上传/下载、显示中文字体、自动登录

文章目录 写在前面putty上传/下载文件1. 下载2. 解压和配置3. 使用sz/rz3.1 下载文件:sz3.2 上传文件:rz 显示中文字体1. 下载合适的字体2. 解压和安装3. putty配置 putty自动登录1. putty配置2. putty快捷方式配置3. 使用putty 写在后面 写在前面 一篇博客介绍了12种SSH终端工…

力扣刷题记录(10)LeetCode:51、37

51. N 皇后 应为各个皇后之间不能同行,所以一行只能有一个皇后。我们可以遍历每一行的各个位置,判断该位置是否可以放置皇后,一行放置一个。当一个皇后的位置已经在这一行确定了,我们就可以遍历下一行来确定下一个皇后在下一行的位…

laravel8 安装swoole扩展

,1,确保你的开发环境满足要求,包括 PHP 版本和相关的扩展。Swoole 扩展要求 PHP 版本为 7.2 或更高,并且需要安装 Swoole 扩展本身。 ,2,打开终端或命令行窗口,并导航到你的 Laravel 项目目录。 ,3,使用 …

✺ch3——数学基础

目录 3D坐标系和点矩阵单位矩阵转置矩阵逆矩阵逆转置矩阵矩阵的运算矩阵加法()矩阵乘法() 常用的变换矩阵平移矩阵缩放矩阵旋转矩阵透视矩阵正射投影矩阵LookAt矩阵 向量加法和减法点积叉积 局部空间和世界空间——模型矩阵M视觉空间和合成相机——模型-视图矩阵MV用GLSL函数构…

MySQL的explain解读记录

简介 Explain是Mysql自带的sql执行的性能分析器。通过 explain 命令获取 select 语句的执行计划。模拟优化器执行SQL语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是结构的性能瓶颈。 Explain可以分析出表的读取顺序、数据读取操作的操作类型、…

域名接入CloudFlare

接入Cloudflare分为两步 Cloudflare中注册站点域名DNS修改 整个过程如下 1.) 访问Cloudflare面板,添加站点 2.) 选择免费版 3.) 查看并明确DNS记录,其中服务的解析地址填写自己实际的服务器ip 4.) 去域名管理控制台,移除旧DNS服务器&#…

YOLOv5改进 | 2023 | CARAFE提高精度的上采样方法(助力细节长点)

一、本文介绍 本文给大家带来的CARAFE(Content-Aware ReAssembly of FEatures)是一种用于增强卷积神经网络特征图的上采样方法。其主要旨在改进传统的上采样方法(就是我们的Upsample)的性能。CARAFE的核心思想是:使用…

轻量封装WebGPU渲染系统示例<52>- Json数据描述材质、纹理等3D渲染场景信息

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/DataDrivenScene3.ts 当前示例运行效果: ​​​​​​​ Json数据: {"renderer": {"mtplEnabled": true,"camera": {"eye&quo…

16、vue3(十六):数据大屏(一):尺寸适配,水球图,柱形图,饼状图、图例

目录 一、尺寸适配解决方案 1.vw和vh 2.scale 二、数据大屏顶部搭建 1.思路分析

lightdb mysql模式下的datediff

文章目录 背景MySQL行为LightDB MySQL兼容模式行为DATEDIFF 背景 在信创适配中,有从MySQL迁移过来的程序,其中程序涉及日期加减数字的场景和使用datediff函数的场景。因此在LightDB-X 23.4版本中,MySQL兼容模式下对日期加减数字做了支持&…

[原创][R语言]股票分析实战[2]:周级别涨幅趋势的相关性

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、D…

频谱论文:面向频谱地图构建的频谱态势生成技术研究

#频谱# [1]李竟铭.面向频谱地图构建的频谱态势生成技术研究.2019.南京航空航天大学,MA thesis.doi:10.27239/d.cnki.gnhhu.2019.000556. (南京航空航天大学) 频谱地图是对无线电环境的抽象表达,它可以直观、多维度地展现频谱态势信息&…

RabbitMq交换机详解

目录 1.交换机类型2.Fanout交换机2.1.声明队列和交换机2.2.消息发送2.3.消息接收2.4.总结 3.Direct交换机3.1.声明队列和交换机3.2.消息接收3.3.消息发送3.4.总结 4.Topic交换机4.1.说明4.2.消息发送4.3.消息接收4.4.总结 5.Headers交换机5.1.说明5.2.消息发送5.3.消息接收5.4.…

React 实现列表页和列表详情页功能

1.简介 本篇文章将会基于react 实现列表页和列表详情的功能,后续会完善更多的功能细节。 2.实现 a.app.js 入口类,实现路由功能 import ./App.css; import {BrowserRouter, Route, Routes} from react-router-dom; import {UserList} from "./p…

python渗透测试入门——流量嗅探器

1.代码及代码讲解。 代码编写工具:VsCode (1)socket嗅探器 首先第一个脚本是最简单的原始socket嗅探器,它只会读一个数据包,然后直接退出: import socket import os#host to listen on HOST #这里输入…

Redis Cluster集群搭建 三主三从

Redis包下载 Linux: http://download.redis.io/releases/ Mac or Windows: https://redis.io/download/ 2.下载后解压进入文件夹(本次我的Redis版本是6.2.14版本) /redis/redis-6.2.14 开始安装 make instarll修改配置文件复制redis.conf 6…

Mysql适用Sql语句对数据库表的字段进行增加、删除和修改等一系列操作

对表字段进行增加:需要指定操作的表名,新增字段的字段名以及字段数据类型。 alter table TableName add column FieldName FieldType 对表字段进行删除:需要指定操作的表名,想要删除的字段名。 alter table TableName drop FieldN…

STM32F103RCT6开发板M3单片机教程04--按键检测

原画图讲解 本教程使用是(光明谷SUN_STM32mini开发板) 首先了硬件连接原理,STM32F103RCT6开发板是mini最小系统板,板子在没并有按键。需要自行用面包板搭建。 硬件连接: PC10 -> KEY1 (MCU内部上拉…

【PostgreSQL】从零开始:(十一)PostgreSQL-Dropdb命令删除数据库

dropdb命令删除数据库 命令 [postgrespostgre-sql bin]$ dropdb --help dropdb removes a PostgreSQL database.Usage:dropdb [OPTION]... DBNAMEOptions:-e, --echo show the commands being sent to the server-f, --force try to terminate …