java.lang.IllegalStateException Expected lazy evaluation to yield a non-null value but got null!

一、问题描述

最近一个老项目线上出现一个问题,偶发性的出现mongo入库没有入成功,查看日志,得到如下报错:

java.lang.IllegalStateException: Expected lazy evaluation to yield a non-null value but got null!
at org.springframework.data.util.Lazy.get(Lazy.java:97)
at org.springframework.data.mapping.model.AnnotationBasedPersistentProperty.isWritable(AnnotationBasedPersistentProperty.java:211)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeProperties(MappingMongoConverter.java:533)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:524)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:497)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeCollectionInternal(MappingMongoConverter.java:744)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createCollection(MappingMongoConverter.java:660)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:574)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeProperties(MappingMongoConverter.java:548)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:524)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:497)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:441)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:78)
at org.springframework.data.mongodb.core.EntityOperations$MappedEntity.toMappedDocument(EntityOperations.java:509)
at org.springframework.data.mongodb.core.MongoTemplate.doInsert(MongoTemplate.java:1234)
at org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:1171)

二、问题排查

首先找到报错的那行代码 Lazy 类的 get 方法的97行

image-20241030140929213

这里的value返回了null,继续看 getNullable() 方法

image-20241030141104608

正常情况应该返回的是 supplier.get() 的返回值,在 AnnotationBasedPersistentProperty 类的 isWritable,可以看到这个 supplier

image-20241030141330452

相当于一个懒加载的方式,如果正常走到 value = supplier.get(); 是不可能返回 null 的,所以一定是 resolvedtrue,导致走到了if语句里,返回了this.value,我们看下这几个变量的初始化值

image-20241030141640025

虽然 value 初始化是 null,但是 resolvedfalse

分析下这里代码的用处,通过 resolved 来做一个懒加载的标记,一开始 resolvedfalse,代码会跳过if,给 value 赋值,然后把 resolved 修改成 true,下次再获取时 resolvedtrue,可以直接获取到赋过值的 value,从而达到懒加载的目的,看似没有什么问题,但是在多线程环境下,就有问题了,结合项目里,mongo插入确实是在线程池里操作的。

所以猜测这是个 springbug,并且这个项目是个老项目,spring的版本较低,猜测估计在新版本中已经修复,去看了下新版本的代码

image-20241030142536994

果然在新版本中 resolved 使用了 volatile 修饰,具体可以参考 https://github.com/spring-projects/spring-data-commons/commit/a442b9002181fa6461490d105a28dd187dd3c38d

三、解决问题

升级 spring 的版本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天进步亿点点的小码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值