0
  • 异常堆栈java.lang.IllegalStateException: Expected lazy evaluation to yield a non-null value but got null!
    at org.springframework.data.util.Lazy.get(Lazy.java:66)
    at org.springframework.data.mapping.model.AnnotationBasedPersistentProperty.isWritable(AnnotationBasedPersistentProperty.java:211)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeProperties(MappingMongoConverter.java:490)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:481)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:455)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:399)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:78)
    at org.springframework.data.mongodb.core.MongoTemplate.toDocument(MongoTemplate.java:1071)
    at org.springframework.data.mongodb.core.MongoTemplate.doInsertBatch(MongoTemplate.java:1164)
    at org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:1116)
  • 问题定位:

org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#isWritable这个对象内部维护了一个lambda表达式,是懒加载方式获取的。

private final Lazy<Boolean> isWritable = Lazy
      .of(() -> !isTransient() && !isAnnotationPresent(ReadOnlyProperty.class));
public T get() {

   T value = getNullable();

   if (value == null) {
      throw new IllegalStateException("Expected lazy evaluation to yield a non-null value but got null!");
   }

   return value;
}
@Nullable
private T getNullable() {

T value = this.value;

if (this.resolved) {
return value;
}

value = supplier.get();

this.value = value;
this.resolved = true;

return value;
}

Lazy内部的getNullable里面会设置解析标记,单线程情况下面,一切都是正常的,多线程情况下面,怀疑是resolved这个标记被刷回内存回内存导致的,而value还是在线程本地缓存中,原因有可能是jvm重排序,导致以上的顺序问题。

以上是本渣渣的猜测,因为是生产环境的,本地jvm无法验证,而且出现概率很低,只有在启动的时候出现过一次。希望有大神帮助解答。

Answered question