Spring缓存抽象:如何处理java.util.Optional<T>

Spring Cache Abstraction: How to Deal With java.util.Optional<T>

我们的代码库中有很多代码类似于以下界面:

public interface SomethingService {
    @Cacheable(value = "singleSomething")
    Optional<Something> fetchSingle(int somethingId);

    // more methods...
}

只要我们只使用本地缓存,这就可以正常工作。但是,一旦我们使用像 Hazelcast 这样的分布式缓存,事情就会开始崩溃,因为 java.util.Optional<T> 不可序列化,因此无法缓存。

到目前为止我已经提出来解决这个问题:

  1. 从方法定义中删除 java.util.Optional<T> 并改为检查可信赖的 null.
  2. 在缓存实际值之前展开 java.util.Optional<T>

我想避免 (1),因为它会涉及大量重构。而且我不知道如何在不实现我自己的 org.springframework.cache.Cache.

的情况下完成 (2)

我还有哪些其他选择?我更喜欢适用于大多数分布式缓存(Hazelcast、Infinispan 等)的通用 (Spring) 解决方案,但我也会接受仅限 Hazelcast 的选项。

一个潜在的解决方案是为 Optional 类型注册一个序列化程序。 Hazelcast 有一个灵活的序列化 API,你可以为任何类型注册一个序列化器。

有关详细信息,请参阅以下示例: https://github.com/hazelcast/hazelcast-code-samples/tree/master/serialization/stream-serializer

所以像这样:

public class OptionalSerializer implements StreamSerializer<Optional> {

@Override
public void write(ObjectDataOutput out, Optional object) throws IOException {
    if(object.isPresent()){
        out.writeObject(object.get());
    }else{
        out.writeObject(null);
    }
}

@Override
public Optional read(ObjectDataInput in) throws IOException {
    Object result = in.readObject();
    return result == null?Optional.empty():Optional.of(result);
}

@Override
public int getTypeId() {
    return 0;//todo:
}

@Override
public void destroy() {

}
}

但是这个解决方案并不完美,因为这个可选的东西将成为实际存储的一部分。所以在内部也存储了 Optional 包装器,这可能会导致问题,例如查询。