使用Spring Cache缓存Java 8可选

Roi*_*zra 8 spring spring-cache

我有一个方法:

@Cacheable(key = "#jobId")
public Optional<JobInfo> getJobById(String jobId) {
    log.info("Querying for job " + jobId);
    counterService.increment("queryJobById");
    Job job = jobsRepository.findOne(jobId);
    if (job != null) {
        return Optional.of(createDTOFromJob(job));
    }
    return Optional.empty();
}
Run Code Online (Sandbox Code Playgroud)

当我尝试检索缓存的项目时,我收到以下异常:

2016-01-18 00:01:10 ERROR [trace =,span =] http-nio-8021-exec-2 [dispatcherServlet]:182 - Servlet [dispatcherServlet]的Servlet.service()在路径[]的上下文中抛出异常[请求处理失败; 嵌套异常是org.springframework.data.redis.serializer.SerializationException:无法序列化; 嵌套异常是org.springframework.core.serializer.support.SerializationFailedException:无法使用DefaultSerializer序列化对象; 嵌套异常是java.lang.IllegalArgumentException:DefaultSerializer需要一个Serializable有效负载,但是收到一个类型为[java.util.Optional]的对象,其根本原因是java.lang.IllegalArgumentException:DefaultSerializer需要一个Serializable有效负载但是收到了一个类型为[java的对象] .util.Optional]

小智 11

只需在 DTO 中实现 Serializable 接口

@Document(collection = "document_name")
public class Document implements Serializable {

    private static final long serialVersionUID = 7156526077883281623L;
Run Code Online (Sandbox Code Playgroud)


Cyr*_*ril 7

Spring支持缓存可选.问题是您的Redis序列化程序(可能是JdkSerializationRedisSerializer).它使用基于Java的序列化,要求类可以序列化.您可以通过将RedisCacheManager配置为使用没有此限制的其他序列化程序来解决此问题.例如,您可以使用Kryo(com.esotericsoftware:kryo:3.0.3):

@Bean
RedisCacheManager redisCacheManager (RedisTemplate<Object, Object> redisOperations) {
    // redisOperations will be injected if it is configured as a bean or create it: new RedisTemplate()...
    redisOperations.setDefaultSerializer(new RedisSerializer<Object>() {
        //use a pool because kryo instances are not thread safe
        KryoPool kryoPool = new KryoPool.Builder(Kryo::new).build();

        @Override
        public byte[] serialize(Object o) throws SerializationException {
            ByteBufferOutput output = new ByteBufferOutput();
            Kryo kryo = kryoPool.borrow();
            try {
                kryo.writeClassAndObject(output, o);
            } finally {
                kryoPool.release(kryo);
                output.close();
            }

            return output.toBytes();
        }

        @Override
        public Object deserialize(byte[] bytes) throws SerializationException {
            if(bytes.length == 0) return null;

            Kryo kryo = kryoPool.borrow();
            Object o;
            try {
                o = kryo.readClassAndObject(new ByteBufferInput(bytes));
            } finally {
                kryoPool.release(kryo);
            }
            return o;
        }
    });

    RedisCacheManager redisCacheManager = new RedisCacheManager(redisOperations);
    redisCacheManager.setCachePrefix(new DefaultRedisCachePrefix("app"));
    redisCacheManager.setTransactionAware(true);
    return redisCacheManager;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这只是一个例子,我没有测试这个imeplementation.但我在生产中使用Kryo序列化程序以相同的方式使用Spring进行redis缓存.


小智 5

因为你的序列化对象没有实现RedisSerializer,或者你可以扩展类JdkSerializationRedisSerializer,它已经实现了RedisSerializer。

示例代码:

import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

public class YourDTOObject  extends JdkSerializationRedisSerializer implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

....
}
Run Code Online (Sandbox Code Playgroud)

更多细节和原理请访问我的博客