当前位置: 首页 > news >正文

Spring编程常见错误50例-Spring Bean依赖注入常见错误(下)

@Value没有注入预期的值

问题

对于@Value可以装配多种类型的数据:

  • 装配对象:
@Value("#{student}")
private Student student;@Bean
public Student student(){Student student = createStudent(1, "xie");return student;
}
  • 装配字符串:
@Value("我是字符串")
private String text;
  • 注入系统参数、环境变量或者配置文件中的值:
@Value("${ip}")
private String ip
  • 注入其他Bean属性:
@Value("#{student.name}")  // student是bean的ID
private String name;

但是使用该注解时遇到以下场景会出现问题:在控制器类中引用配置类中的属性时部分值返回错误

username=admin
password=pass
@RestController
@Slf4j
public class ValueTestController {@Value("${username}")private String username;@Value("${password}")private String password;@RequestMapping(path = "user", method = RequestMethod.GET)public String getUser(){return username + ","  + ", " + password;  // username返回的是运行这段程序的计算机用户名,password能正确返回};}

原因

从下面代码中可以看到@Value的工作分为三个核心步骤:

// DefaultListableBeanFactory#doResolveDependency
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {// ...// ①寻找@ValueObject value = getAutowireCandidateResolver().getSuggestedValue(descriptor);if (value != null) {// ②解析value值if (value instanceof String) {String strVal = resolveEmbeddedValue((String) value);BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);value = evaluateBeanDefinitionString(strVal, bd);}// ③转化Value解析的结果到装配的类型TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());try {return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());}catch (UnsupportedOperationException ex) {...}}// ...
}
  • 寻找@Value:判断属性字段是否标记为@Value
// QualifierAnnotationAutowireCandidateResolver#findValue
@Nullable
protected Object findValue(Annotation[] annotationsToSearch) {if (annotationsToSearch.length > 0) {   // qualifier annotations have to be localAnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(// valueAnnotationType即为@ValueAnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);if (attr != null) {return extractValue(attr);}}return null;
}
  • 解析@Value的字符串值:如果字段标记了@Value,则可拿到对应的字符串值,然后就可以根据字符串值去做解析,解析结果可能是字符串,也可能是对象

  • 将解析结果转化为要装配的对象的类型:

分析完对应的步骤后,可以定位到问题原因在解析@Value指定字符串过程中,对${xxx}的查找不局限在application.properties,而是针对多个源,这些源在启动时被有序固定,所以在查找时也是按序查找的。当查找到systemEnvironment时发有个username和配置文件中的重合
在这里插入图片描述

// PropertySourcesPropertyResolver#getProperty
@Nullable
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {if (this.propertySources != null) {for (PropertySource<?> propertySource : this.propertySources) {if (logger.isTraceEnabled()) {logger.trace("Searching for key '" + key + "' in PropertySource '" +propertySource.getName() + "'");}Object value = propertySource.getProperty(key);if (value != null) {if (resolveNestedPlaceholders && value instanceof String) {value = resolveNestedPlaceholders((String) value);}logKeyFound(key, propertySource, value);return convertValueIfNecessary(value, targetValueType);}}}if (logger.isTraceEnabled()) {logger.trace("Could not find key '" + key + "' in any property source");}return null;
}

解决方式

避免存在与系统或环境变量有同名的配置

myname=admin
password=pass

错乱的注入集合

问题

假设存在多个学生Bean,需找出来并存储到List里并在控制器类中输出:

// 可以理解为收集方式
@Bean
public Student student1(){return createStudent(1, "psj1");
}@Bean
public Student student2(){return createStudent(2, "psj2");
}private Student createStudent(int id, String name) {Student student = new Student();student.setId(id);student.setName(name);return student;
}
private List<Student> students;public StudentController(List<Student> students){this.students = students;
}@RequestMapping(path = "students", method = RequestMethod.GET)
public String listStudents(){return students.toString();
};

此时需要再增加学生Bean,换了一种方式注入集合类型:

// 可以理解为直接装配方式
@Bean
public List<Student> students(){Student student3 = createStudent(3, "psj3");Student student4 = createStudent(4, "psj4");return Arrays.asList(student3, student4);
}

但上述两种方式都存在,只会输出前面两个学生

原因

  • 进行第一种装配方式时(即收集方式),主要分为以下过程:
// DefaultListableBeanFactory#resolveMultipleBeans
@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {final Class<?> type = descriptor.getDependencyType();if (descriptor instanceof StreamDependencyDescriptor) {...// 装配streamreturn stream;}else if (type.isArray()) {...// 装配数组return result;}else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {// 装配集合// 获取集合的元素类型Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();if (elementType == null) {return null;}// 根据元素类型查找所有的beanMap<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,new MultiElementDescriptor(descriptor));if (matchingBeans.isEmpty()) {return null;}if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}// 转化查到的所有bean放置到集合并返回TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());Object result = converter.convertIfNecessary(matchingBeans.values(), type);...return result;}else if (Map.class == type) {...// 解析mapreturn matchingBeans;}else {return null;}
}
  • 进行第二种装配方式时(即直接装配方式),具体过程在DefaultListableBeanFactory#findAutowireCandidates
  • 当同时满足这两种装配方式时,从下面代码中可以看出它们是不能共存的:
// DefaultListableBeanFactory#doResolveDependency
// 采用收集方式
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {return multipleBeans;
}
// 上述方式不执行才会执行直接装配方式
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

解决方式

对于同一个集合对象的注入不要混合多种注入方式

参考

极客时间-Spring 编程常见错误 50 例

https://github.com/jiafu1115/springissue/tree/master/src/main/java/com/spring/puzzle/class3

相关文章:

Spring编程常见错误50例-Spring Bean依赖注入常见错误(下)

Value没有注入预期的值 问题 对于Value可以装配多种类型的数据&#xff1a; 装配对象&#xff1a; Value("#{student}") private Student student;Bean public Student student(){Student student createStudent(1, "xie");return student; }装配字符…...

SpringBoot整合Canal实现MySQL与ES数据同步

文章目录 SpringBoot项目引入Canal依赖配置文件项目结构设置监听类其余类、接口内容启动类实体类Controller类Mapper接口Serice接口 运行测试 开始之前请确认docker中已运行mysql与canal容器&#xff0c;并完成了监听binlog配置 未完成可移步&#xff1a; Docker部署Canal监听…...

Zookeeper 源码分析流程

文章目录 前言Zookeeper启动加载磁盘数据与客户端的通信交互Leader选举准备节点状态处理总结 前言 Zookeeper 作为分布式协调服务为分布式系统提供了一些基础服务&#xff0c;如&#xff1a;命名服务、配置管理、同步等&#xff0c;使得开发者可以更加轻松地处理分布式问题。 …...

计数排序与基数排序

计数排序与基数排序 计数排序 计数排序&#xff1a;使用一个数组记录序列中每一个数字出现的次数&#xff0c;将该数组的下标作为实际数据&#xff0c;元素的值作为数据出现的次数。例如对于序列[3,0,1,1,3,3,0,2]&#xff0c;统计的结果为&#xff1a; 0出现的次数&#xf…...

Mysql—表操作

目录 1、linux中数据库表名区分大小写&#xff0c;windows不区分2、创建数据库表3、外键4、查看数据表结构5、修改表5.1、修改表名5.2、添加字段5.3、指定位置添加字段5.4、修改字段名称5.5、修改字段类型5.6、修改字段位置5.7、删除字段5.8、修改表存储引擎5.9、删除外键 1、l…...

SpringCloud——微服务

微服务技术栈 在之前的开发过程中&#xff0c;我们将所有的服务都部署在一台服务器中&#xff0c;当我们的服务开始越来越多&#xff0c;业务越来越复杂&#xff0c;当一台服务器不能承担我们的业务的时候&#xff0c;就需要将不同的业务分开部署在不同的服务器上&#xff0c;…...

深入理解Java单例模式和优化多线程任务处理

目录 饿汉模式懒汉模式单线程版多线程版双重检查锁定 阻塞队列 单例模式能保证某个类在程序中只存在唯一一份实例, 而不会创建出多个实例&#xff0c;并提供一个全局访问点。 饿汉模式 类加载的同时&#xff0c;创建实例。 class Singleton {private static final Singlet…...

已解决 Kotlin Error: Type mismatch: inferred type is String but Int was expected

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…...

Web应用系统的小安全漏洞及相应的攻击方式

写作目的 本文讲述一个简单的利用WebAPI来进行一次基本没有破坏力的“黑客”行为。 主要目的如下&#xff1a; 了解什么叫安全漏洞 知道什么是api 了解一些获取api的工具 通过对API的认识了解白盒接口测试基本概念和技术 免责声明&#xff1a; 本文主要是以学习交流为目的&a…...

git工具下载和安装

(1)从git官网下载安装包 然后安装 https://git-scm.com/downloads (2)git 学习参考官方的资料 https://git-scm.com/book/en/v2...

腾讯mini项目-【指标监控服务重构】2023-08-04

今日已办 关于 span-references 的调研 https://github.com/DataDog/dd-trace-js/issues/1761 https://github.com/open-telemetry/opentelemetry-specification/blob/874a451e7f6ac7fc54423ee3f03e5394197be35b/specification/compatibility/opentracing.md#span-references h…...

怎么推广自己抖店的商品?最适合0经验新手操作的办法,来看看

我是王路飞。 抖店开通后&#xff0c;想要把自己店铺的商品卖出去&#xff0c;就需要进行推广了。 但是怎么推广呢&#xff1f; 要么利用抖音的搜索和推荐流量&#xff0c;获取曝光&#xff0c;实现点击和转化。 不过这种玩法有个弊端&#xff0c;就是需要你有一定的电商经…...

线性代数的本质(三)——线性方程组

文章目录 线性方程组高斯消元法初等行变换线性方程组的解向量方程齐次线性方程组的解非齐次线性方程组的解 线性方程组 高斯消元法 客观世界最简单的数量关系是均匀变化的关系。在均匀变化问题中&#xff0c;列出的方程组是一次方程组&#xff0c;我们称之为线性方程组(Linea…...

轻量级性能测试工具 wrk 如何使用?

项目设计之初或者是项目快要结束的时候&#xff0c;大佬就会问我们&#xff0c;这个服务性能测试的结果是什么&#xff0c;QPS 可以达到多少&#xff0c;RPS 又能达到多少&#xff1f;接口性能可以满足未来生产环境的实际情况吗&#xff1f;有没有自己测试过自己接口的吞吐量&a…...

WebGL 视图矩阵、模型视图矩阵

目录 立方体由三角形构成 视点和视线 视点、观察目标点和上方向 视点&#xff1a; 观察目标点&#xff1a; 上方向&#xff1a; 在WebGL中&#xff0c;观察者的默认状态应该是这样的&#xff1a; 视图矩阵程序&#xff08;LookAtTriangles.js&#xff09; 实际上&…...

Python 3 – 文件 readline() 方法

Python 3 – 文件 readline() 方法|极客笔记 # 打开文件 file open("example.txt", "r")# 读取文件中的一行数据 line file.readline() while line:# 移除行尾的换行符print(line.strip())# 读取文件中的下一行数据line file.readline()# 关闭文件 file…...

如何在微软Edge浏览器上一键观看高清视频?

编者按&#xff1a;视频是当下最流行的媒体形式之一。但由于视频压缩、网络不稳定等原因&#xff0c;我们常常可以看到互联网上的很多视频其画面质量并不理想&#xff0c;尤其是在浏览器端&#xff0c;这极大地影响了观看体验。不过&#xff0c;近期微软 Edge 浏览器推出了一项…...

Telegram BoT的主流项目盘点

目录 DeFi 类 数据分析类 空投埋伏交易 其他 Telegram Bot赛道的发展趋势预测 Telegram BoT赛道发展较快&#xff0c;具体来看可以分为DeFi 类、数据分析类、空投埋伏交易类以及其他。 DeFi 类 Unibot&#xff08;交易&#xff09;、Banana Gun、WagieBot&#xff08;交…...

PTA 甲级 1044 Shopping in Mars

题目链接 思路&#xff1a;前缀和滑动窗口 #include<bits/stdc.h> #define MAXN 100010 using namespace std; int a[MAXN];int main(){int n,m;cin>>n>>m;//n数量 m金额for(int i1;i<n;i){int t;cin>>t;a[i]a[i-1]t;//前缀和}vector<pair<in…...

Linux学习之MyCat实现分库分表

环境准备 先准备一套MySQL主从服务器&#xff0c;可参考MySQL主从配置配置MyCat服务 资源下载 网盘链接: https://pan.baidu.com/s/1cLTMH_e1-6loc_gF9ZNHTg?pwda63n 提取码: a63n MyCat配置 # 1&#xff09;安装mycat软件 //安装jdk [rootmycat58 upload]# yum -y insta…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用

前言&#xff1a;我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM&#xff08;Java Virtual Machine&#xff09;让"一次编写&#xff0c;到处运行"成为可能。这个软件层面的虚拟化让我着迷&#xff0c;但直到后来接触VMware和Doc…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space

问题&#xff1a;IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案&#xff1a;将编译的堆内存增加一点 位置&#xff1a;设置setting-》构建菜单build-》编译器Complier...

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器

从本章节开始&#xff0c;进入到函数有多个参数的情况&#xff0c;前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参&#xff0c;ECX是整型的第一个参数的寄存器&#xff0c;那么多个参数的情况下函数如何传参&#xff0c;下面展开介绍参数为整型时候的几种情…...