SpringBoot 05 集成redis实现对象序列化缓存

  • Post author:
  • Post category:其他


1.为什么用Spring Data

Spring Data 的目标是为数据访问提供一个基于Spring的普遍常用的编程模型,同时仍然保留底层数据存储的特殊特性, 它让使用数据访问技术、关系和非关系数据库和基于云的数据服务变得容易,它包含了很多的子项目例如Spring Data JDBC, Spring Data Redis,Spring Data MongoDB等。

Spring Data Redis是Spring Data项目的一个子项目, 它提供了从Spring应用程序对Redis的简单配置和轻松访问的方法,将开发人员从基础设置问题中解放出来。它消除了存储交互所需啊哟的冗余任务和样板代码,使得编写使用 Redis键值存储的Spring 应用程序变得非常容易

2.SpringBoot+Redis 示例

1. 创建SpringBoot项目,参考目录结构如下

pom中增加spring-data-redis依赖,参考Pom.xml如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.boot</groupId>
    <artifactId>demo-redis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-redis</name>
    <description>Demo project for Spring Boot + SpringData Redis</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- redis 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <!-- redis 依赖 -->

        <!-- WEB应用 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

参考application.properties文件

server.port=8002


## Redis数据库索引,默认为0
spring.redis.database=0
## Redis数据库地址,默认为localhost
spring.redis.host=127.0.0.1
## Redis数据库端口,默认为6379
spring.redis.port=6379
# Redis服务器连接密码,默认为空
spring.redis.password=
## Redis连接超时时间,单位毫秒
spring.redis.timeout=3000
## Redis链接超时时间
spring.redis.connect-timeout=3000
## Redis连接池中的最小空闲连接数
spring.redis.jedis.pool.min-idle=0
## Redis连接池中的最大空闲连接数
spring.redis.jedis.pool.max-idle=8


注: 启动SpringBoot后自动装配会加载自动配置类RedisAutoConfiguration ,其上使用了注解@EnableConfigurationProperties(RedisProperties.class), 将RedisProperties配置生效


application.properties的配置信息会注入对象org.springframework.boot.autoconfigure.data.redis。RedisProperties 中,因此其他可用属性(spring.redis.**)可以参考RedisProperties 对象上的批注说明

3. 创建测试类UserDTO

package com.boot.redis.domain;

import java.io.Serializable;

public class UserDTO implements Serializable {

    private Long id;
    private String name;
    private String code;

    //省略getter和setter

    @Override
    public String toString() {
        return "UserDTO{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", code='" + code + '\'' +
                '}';
    }
}

通过@Configuration注解创建Bean对象RedisTemplate,

package com.boot.redis.conf;

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.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();
        template.setValueSerializer(jdkSerializer);
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

4. 创建测试Controller,并注入RedisTemplate,这个类只是用于测试,实际项目中并不会以此方式处理登录信息

/login 用于模拟登录

  • @RequestParam表示登录请求中如果没有带参数,默认为zhangsan ,即/login和/login?username=zhangsan相同

  • index 每次自增长1,用于模拟不同的ID

  • redisTemplate #execute执行的时候先生成KEY 然后将对象系列化后保存到Redis中

/login 用于模拟获取登录信息

  • @RequestParam表示登录请求中如果没有带参数,默认为1,即/get和/get?uuserid=1相同
  • redisTemplate #execute执行的时候先获取Redis中的值然后再转换成对象返回
package com.boot.redis.controller;


import com.boot.redis.domain.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class LoginController {

    //顺序生成ID,用于测试
    private static Long index = 1L;

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/login")
    public String login(@RequestParam(value = "username", defaultValue = "zhangsan") String name) {
        UserDTO user = new UserDTO();
        user.setCode(""+1000+index);
        user.setName(name);
        user.setId(index++);

        redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {

                byte[] key = redisTemplate.getStringSerializer().serialize("user.id." + user.getId());

                JdkSerializationRedisSerializer s = (JdkSerializationRedisSerializer) redisTemplate.getValueSerializer();

                connection.set(key, s.serialize(user));
                System.out.println("add");
                return null;
            }
        });

        return String.format("success", name);
    }

    @GetMapping("/get")
    public String get(@RequestParam(value = "userid", defaultValue = "1") String userId) {

        Object object = redisTemplate.execute(new RedisCallback() {

            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {
                byte[] key = redisTemplate.getStringSerializer().serialize("user.id." + userId);
                if (connection.exists(key)) {
                    JdkSerializationRedisSerializer s = (JdkSerializationRedisSerializer) redisTemplate.getValueSerializer();
                    return s.deserialize(connection.get(key));
                }
                return null;
            }
        });

        if (object == null) {
            return "null";
        } else {
            return ((UserDTO) object).toString();
        }

    }
}

测试:

先启动一个Redis Server ,这部分内容可以参考

Redis 安装_学然后知不足!-CSDN博客

,这里不再重复说明


1. 测试请求 :http://127.0.0.1:8002/login?username=zhangsan


2. 测试请求:http://127.0.0.1:8002/get?userid=1

3. 通过RedisDesktopManager工具查看Redis中的信息

3.参考源码


https://github.com/PNZBEIJINGL/springboot/tree/master/demo-redis

4.常见问题

ClassNotFoundException: org.apache.commons.pool.impl.GenericObjectPool$Config

Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool.impl.GenericObjectPool$Config
	at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

Spring-Data-Redis版本问题,一般是commons-pool2不匹配引起的,可以查看Maven官网中建议的匹配版本, 例如下图


前一篇:SpringBoot 04 集成Flyway实现数据库版本控制