SpringBoot自定义redisTemplate的key和value的序列化方式

简介: SpringBoot自定义redisTemplate的key和value的序列化方式

在SpringBoot的redisTemplate在redis当中存入数据的时候,能看到key和value被序列化,我们基本上很难判断这个缓存是干什么用的,所以我们需要修复它:

解决这个问题我们需要自定义一个序列化器RedisJsonSerializerImpl,其中还有一个内部类:

/**
 * <p>
 * 序列化对象,将对象存入这个类中然后存入redis
 * </p>
 *
 * @author XiaoHH
 * @version 1.0
 * @date 2021-12-07 星期二 14:45:54
 */
static class SerializerObject {
    /**
     * 无参构造
     */
    public SerializerObject() {
    }
    /**
     * 全参构造
     *
     * @param className  对象的类名
     * @param jsonObject 将内容对象转换为json字符串之后的结果
     */
    public SerializerObject(String className, String jsonObject) {
        this.className = className;
        this.jsonObject = jsonObject;
    }
    /**
     * 对象的类名
     */
    private String className;
    /**
     * 将内容对象转换为json字符串之后的结果
     */
    private String jsonObject;
    public String getClassName() {
        return className;
    }
    public SerializerObject setClassName(String className) {
        this.className = className;
        return this;
    }
    public String getJsonObject() {
        return jsonObject;
    }
    public SerializerObject setJsonObject(String jsonObject) {
        this.jsonObject = jsonObject;
        return this;
    }
    /**
     * 将本对象转换为json格式
     *
     * @return 转换后的json
     */
    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

RedisJsonSerializerImpl实现了org.springframework.data.redis.serializer.RedisSerializer,并且实现下面两个方法,serialize方法定义了序列化对象(将对象从Java程序中存入缓存中),deserialize用户反序列化对象(将缓存中读取对象并转换为Java对象):

/**
 * 将对象序列化成一个 byte 数组
 *
 * @param t 对象的实例
 * @return 序列化后的结果
 * @throws SerializationException 可能会抛出序列化异常
 */
@Override
public byte[] serialize(T t) throws SerializationException {
    // 如果对象为空,那么就返回一个空的byte数组就好了
    if (null == t) return new byte[0];
    // 获取序列化后的对象
    String resultObject = new SerializerObject(t.getClass().getName(), JSON.toJSONString(t)).toString();
    return resultObject.getBytes(StandardCharsets.UTF_8);
}
/**
 * 将一个已经序列化好后的对象转换为一个真实的对象,并返回它
 *
 * @param bytes 序列化后的结果
 * @return 反序列化后的结果
 * @throws SerializationException 可能会抛出序列化异常
 */
@Override
public T deserialize(byte[] bytes) throws SerializationException {
    if (CollectionUtils.isNull(bytes)) return null;
    // 将其反序列化成一个字符串
    SerializerObject resultObject = JSON.parseObject(new String(bytes, StandardCharsets.UTF_8), SerializerObject.class);
    try {
        return JSON.parseObject(resultObject.jsonObject, (Type) Class.forName(resultObject.className));
    } catch (ClassNotFoundException e) {
        log.error("类未找到:" + resultObject.className, e);
        return null;
    }
}

类完整的代码如下:

package love.xiaohh.cost.utils.storage;
import com.alibaba.fastjson.JSON;
import love.xiaohh.cost.utils.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
/**
 * <p>
 * 存入redis的时候处理对象格式化的问题
 * </p>
 *
 * @author XiaoHH
 * @version 1.0
 * @date 2021-12-07 星期二 14:33:54
 * @file RedisJsonSerializerImpl.java
 */
public class RedisJsonSerializerImpl<T> implements RedisSerializer<T> {
    /**
     * 记录日志的对象
     */
    private static final Logger log = LoggerFactory.getLogger(RedisJsonSerializerImpl.class);
    /**
     * 将对象序列化成一个 byte 数组
     *
     * @param t 对象的实例
     * @return 序列化后的结果
     * @throws SerializationException 可能会抛出序列化异常
     */
    @Override
    public byte[] serialize(T t) throws SerializationException {
        // 如果对象为空,那么就返回一个空的byte数组就好了
        if (null == t) return new byte[0];
        // 获取序列化后的对象
        String resultObject = new SerializerObject(t.getClass().getName(), JSON.toJSONString(t)).toString();
        return resultObject.getBytes(StandardCharsets.UTF_8);
    }
    /**
     * 将一个已经序列化好后的对象转换为一个真实的对象,并返回它
     *
     * @param bytes 序列化后的结果
     * @return 反序列化后的结果
     * @throws SerializationException 可能会抛出序列化异常
     */
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (CollectionUtils.isNull(bytes)) return null;
        // 将其反序列化成一个字符串
        SerializerObject resultObject = JSON.parseObject(new String(bytes, StandardCharsets.UTF_8), SerializerObject.class);
        try {
            return JSON.parseObject(resultObject.jsonObject, (Type) Class.forName(resultObject.className));
        } catch (ClassNotFoundException e) {
            log.error("类未找到:" + resultObject.className, e);
            return null;
        }
    }
    /**
     * <p>
     * 序列化对象,将对象存入这个类中然后存入redis
     * </p>
     *
     * @author XiaoHH
     * @version 1.0
     * @date 2021-12-12 星期日 09:45:54
     */
    static class SerializerObject {
        /**
         * 无参构造
         */
        public SerializerObject() {
        }
        /**
         * 全参构造
         *
         * @param className  对象的类名
         * @param jsonObject 将内容对象转换为json字符串之后的结果
         */
        public SerializerObject(String className, String jsonObject) {
            this.className = className;
            this.jsonObject = jsonObject;
        }
        /**
         * 对象的类名
         */
        private String className;
        /**
         * 将内容对象转换为json字符串之后的结果
         */
        private String jsonObject;
        public String getClassName() {
            return className;
        }
        public SerializerObject setClassName(String className) {
            this.className = className;
            return this;
        }
        public String getJsonObject() {
            return jsonObject;
        }
        public SerializerObject setJsonObject(String jsonObject) {
            this.jsonObject = jsonObject;
            return this;
        }
        /**
         * 将本对象转换为json格式
         *
         * @return 转换后的json
         */
        @Override
        public String toString() {
            return JSON.toJSONString(this);
        }
    }
}

然后我们定义一个RedisConfig,将设置这个序列化对象:

package love.xiaohh.cost.configurations;
import love.xiaohh.cost.constants.Constants;
import love.xiaohh.cost.utils.storage.RedisJsonSerializerImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
 * <p>
 * redis相关的配置类
 * </p>
 *
 * @author XiaoHH
 * @version 1.0
 * @date 2021-12-12 星期日 09:54:59
 * @file RedisConfig.java
 */
@Configuration
public class RedisConfig {
    /**
     * 定义redisTemplate对象,用于访问redis
     *
     * @param redisConnectionFactory redis的链接工厂,从Spring容器中获取
     * @return 自行配置好的redis访问对象
     */
    @Bean(Constants.REDISTEMPLATE)
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 缓存操作对象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        // 设置链接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 键的序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 值的序列化器,这里我们用的是我们自己配置好的
        redisTemplate.setValueSerializer(new RedisJsonSerializerImpl<>());
        return redisTemplate;
    }

其中key的序列化器使用自带的 StringRedisSerializer,然后value序列化使用我们自定义的 RedisJsonSerializerImpl,这个类就定义好了,我们运行看看效果:

可以发现key和value的可观测性提高了许多,好了下课

相关文章
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
1138 0
|
8月前
|
存储 NoSQL Java
配置RedisTemplate序列化机制
通过上述步骤,你可以灵活配置RedisTemplate的序列化机制,根据应用需求选择合适的序列化器,从而确保数据在Redis中的存储和读取效率最优化。配置合适的序列化机制对于性能和存储效率至关重要,而且这样可以确保数据在存储和传输过程中的结构清晰和一致性。
558 11
|
9月前
|
存储 NoSQL Java
RedisTemplate序列化问题排查与优化建议。
最后,对于序列化问题的深入排查与优化,建议编写具有代表性的单元测试,以验证RedisTemplate配置的正确性和效能。此外,可以在非生产环境中测试不同的序列化策略,找到最适合当前应用场景的序列化方式。通过不断迭代和优化,达到持续提高数据存取能力的目标。
372 13
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
1391 2
|
Java Maven 开发者
编写SpringBoot的自定义starter包
通过本文的介绍,我们详细讲解了如何创建一个Spring Boot自定义Starter包,包括自动配置类、配置属性类、`spring.factories`文件的创建和配置。通过自定义Starter,可以有效地复用公共配置和组件,提高开发效率。希望本文能帮助您更好地理解和应用Spring Boot自定义Starter,在实际项目中灵活使用这一强大的功能。
1174 17
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——拦截自定义异常
本文介绍了在实际项目中如何拦截自定义异常。首先,通过定义异常信息枚举类 `BusinessMsgEnum`,统一管理业务异常的代码和消息。接着,创建自定义业务异常类 `BusinessErrorException`,并在其构造方法中传入枚举类以实现异常信息的封装。最后,利用 `GlobalExceptionHandler` 拦截并处理自定义异常,返回标准的 JSON 响应格式。文章还提供了示例代码和测试方法,展示了全局异常处理在 Spring Boot 项目中的应用价值。
620 0
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
2441 15
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
786 2
|
安全 Java 应用服务中间件
如何将Spring Boot应用程序运行到自定义端口
如何将Spring Boot应用程序运行到自定义端口
1612 0
|
前端开发 Java 数据库
springBoot:template engine&自定义一个mvc&后端给前端传数据&增删改查 (三)
本文介绍了如何自定义一个 MVC 框架,包括后端向前端传递数据、前后端代理配置、实现增删改查功能以及分页查询。详细展示了代码示例,从配置文件到控制器、服务层和数据访问层的实现,帮助开发者快速理解和应用。
256 0

热门文章

最新文章