IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 使用SpringCache实现缓存,自定义序列化方式,解决序列化bug -> 正文阅读

[Java知识库]使用SpringCache实现缓存,自定义序列化方式,解决序列化bug

作者:token annotation punctuation

使用SpringCache实现缓存,自定义序列化方式,解决序列化bug

在学习SpringCache之前,很多同学会使用硬编码的方式去给代码设置缓存,缓存操作和业务逻辑之间的代码耦合度高,对业务逻辑有较强的侵入性。

当然我们也可以结合Spring的AOP和自定义注解去实现缓存。

那么在Spring中,我们可以直接使用SpringCache来完成我们在项目中数据的缓存操作。

缓存声明

名称解释
@Cacheable根据方法的请求参数对其结果进行缓存,下次同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法
@CachePut根据方法的请求参数对其结果进行缓存,它每次都会触发真实方法的调用
@CacheEvict根据一定的条件删除缓存
@Caching组合多个缓存注解
@CacheConfig类级别共享缓存相关的公共配置

相关demo

Controller

@RequestMapping(value = "/user")
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping(value = "/userInfo")
    public JSONObject userInfo (Long id) {
        JSONObject jsonRes = new JSONObject();
        User user = userService.userInfo(id);
        jsonRes.put("userInfo", user);
        return jsonRes;
    }

    @PostMapping(value = "/addUser")
    public JSONObject addUser (@RequestBody User user) {
        JSONObject jsonRes = new JSONObject();
        User userRes = userService.addUser(user);
        jsonRes.put("addUser", userRes);
        return jsonRes;
    }

    @PostMapping(value = "/editUser")
    public JSONObject editUser (@RequestBody User user) {
        JSONObject jsonRes = new JSONObject();
        User userRes = userService.editUser(user);
        jsonRes.put("editUser", userRes);
        return jsonRes;
    }

    @GetMapping(value = "/delUser")
    public JSONObject delUser (Long id) {
        JSONObject jsonRes = new JSONObject();
        userService.delUser(id);
        jsonRes.put("delUser", id);
        return jsonRes;
    }

}

Service

@Service
public class UserService {

    @Cacheable(value = "user_cache", key = "#id")
    public User userInfo (Long id) {
        User user = new User();
        user.setId(id);
        user.setName("小黑");
        user.setSex("男");
        user.setAge(18);
        System.out.println("用户详情:" + JSON.toJSONString(user));
        return user;
    }

    public User addUser (User user) {
        System.out.println("添加用户:" + JSON.toJSONString(user));
        return user;
    }

    @CachePut(value = "user_cache", key = "#user.id")
    public User editUser (User user) {
        System.out.println("修改用户:" + JSON.toJSONString(user));
        return user;
    }

    @CacheEvict(value = "user_cache", key = "#id")
    public void delUser (Long id) {
        System.out.println("删除用户:" + id);
    }

}

Configuration

spring.cache.type=redis
spring.redis.host=127.0.0.1
// 自定义序列化方式
public class MyFastJsonRedisSerializer<T> implements RedisSerializer<T> {

    private final Type type;

    public MyFastJsonRedisSerializer(Type type) {
        this.type = type;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        return JSON.toJSONBytes(t);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        return JSON.parseObject(bytes,type);
    }
}
package com.wazk.demo.conf;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.ReflectionUtils;

import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @class: CacheConfig
 * @description: TODO
 * @author: wazk
 * @version: 1.0
 * @date: 2022/4/17 5:42 下午
 */
@Configuration
public class CacheConfig{

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;
    @Autowired
    private ApplicationContext applicationContext;

    // SpringCache缓存的序列化处理
    @Bean
    public CacheManager cacheManager() {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(120L)) //缓存20秒钟
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new MyFastJsonRedisSerializer<>(Object.class)));
        return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).withInitialCacheConfigurations(buildInitCaches()).build();
    }

    private Map<String, RedisCacheConfiguration> buildInitCaches() {
        HashMap<String, RedisCacheConfiguration> cacheConfigMap = new HashMap<>();
        Arrays.stream(applicationContext.getBeanNamesForType(Object.class))
                .map(applicationContext::getType).filter(Objects::nonNull)
                .forEach(clazz -> {
                            ReflectionUtils.doWithMethods(clazz, method -> {
                                ReflectionUtils.makeAccessible(method);
                                Cacheable cacheable = AnnotationUtils.findAnnotation(method, Cacheable.class);
                                if (Objects.nonNull(cacheable)) {
                                    for (String cache : cacheable.cacheNames()) {
                                        RedisSerializationContext.SerializationPair<Object> sp = RedisSerializationContext.SerializationPair
                                                .fromSerializer(new MyFastJsonRedisSerializer<>(method.getGenericReturnType()));
                                        cacheConfigMap.put(cache, RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(sp));
                                    }
                                }
                            });
                        }
                );
        return cacheConfigMap;
    }

}

序列化问题处理

FastJsonRedisSerializerJackson2JsonRedisSerializer

这两个序列化器在进行非集合的数据缓存后,调用上述代码中获取数据时,会报类型转换异常,但如果是集合数据的时候却是正常的,且是常规的json字符串

  • FastJson报java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.cache.demo.SimpleBook
  • Jackson报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.cache.demo.SimpleBook

GenericFastJsonRedisSerializerGenericJackson2JsonRedisSerializer

这两个序列化器在序列化后的数据中携带了类型的信息@class,同时为非json格式字符串,当json的工具不一样时会导致解析失败

综合上述的问题,所以改进的思路是自定义一个序列化器,扫描注解上的返回类型进行一一对应的解析

故此上述代码最后进行了自定义序列化方式的操作,也就是用咱们最普通的序列化方式,转为JSON字符串

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:27:33  更:2022-04-18 17:29:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:19:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码