美文网首页
SpringBoot集成Cache缓存(Redis缓存,Redi

SpringBoot集成Cache缓存(Redis缓存,Redi

作者: 木木与呆呆 | 来源:发表于2021-09-14 14:51 被阅读0次

1.说明

SpringBoot集成Redis缓存,
首先创建一个Spring Boot工程,
使用Maven向导方式创建:
SpringBoot集成Maven工程
然后引入redis的spring boot starter,
演示RedisTemplate的基本用法。

需要注意的是,
在SpringBoot1.x使用的是Jedis,
在SpringBoot2.x使用的是Lettuce。
下面演示的版本是SpringBoot2.x,
但是只使用RedisTemplate无需关注Lettuce。

2.新增pom依赖

修改pom.xml文件
增加spring-boot-starter-data-redis依赖,
以及Redis连接池commons-pool2依赖:

<!-- spring redis starter -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- spring2.X集成redis所需common-pool2 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

3.新增Redis配置类

新增配置类RedisConfig.java,
用于创建RedisTemplate实例,
注意设置Key和Value的序列化方式,
这样Redis保存的就是JSON格式的数据,
而不是看不懂的JDK序列化数据:

package com.yuwen.spring.demo.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

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

        // 设置key序列化方式
        StringRedisSerializer stringSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringSerializer);
        // 设置value序列化方式
        GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
        template.setValueSerializer(jsonSerializer);

        // 初始化,并且填充参数默认值
        template.afterPropertiesSet();
        return template;
    }
}

另外说下RedisTemplate的自动配置,
在RedisAutoConfiguration类中自动生成了
一个RedisTemplate和一个StringRedisTemplate,
但是RedisTemplate的泛型是<Object,Object>,
并且没有设置key及value的序列化方式,
不方便编码,需要编写类型转换的代码,
所以自定义了一个泛型为<String,Object>的RedisTemplate,
后面的代码就是注入这个RedisTemplate来使用的,
由于@ConditionalOnMissingBean注解的作用,
Spring容器中已经有了RedisTemplate对象,
这个自动配置类的RedisTemplate不会被实例化。

4.使用RedisTemplate

在业务类UserSortControllerImpl.java中,
使用Spring自动注入RedisTemplate<String, Object>,
这个业务使用Redis的Zset对用户进行排序,
按照用户的id存入Redis的有序集合,
然后按照id从小到大批量查询用户数据,
并且可以指定id开始和结束范围:

package com.yuwen.spring.demo.controller.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
import com.yuwen.spring.demo.controller.UserSortController;
import com.yuwen.spring.demo.entity.User;

@RestController
public class UserSortControllerImpl implements UserSortController {

    // 保存在Redis中的user集合的key
    private static final String ZSET_USER = "zset_user";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void createUser(User user) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        // 重复添加相同的user会覆盖
        zset.add(ZSET_USER, user, user.getId());
        System.out.println("add user " + user + "to redis zset_user");
    }

    @Override
    public List<User> getAllUser(Integer min, Integer max) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();

        // 如果边界为空,使用负无穷和正无穷填充
        if (min == null) {
            min = Integer.MIN_VALUE;
        }

        if (max == null) {
            max = Integer.MAX_VALUE;
        }

        Set<Object> userObjects = zset.rangeByScore(ZSET_USER, min, max);
        System.out.println("getAllUser users=" + userObjects);

        List<User> users = Lists.transform(new ArrayList<>(userObjects), object -> (User) object);

        return users;
    }
}

注意RedisTemplate的泛型不能写错,
否则Spring无法注入对应的单例,
createUser方法把用户存入Redis,并使用Id作为排序参数,
getAllUser方法按照ID访问从Redsi查询数据。

5.Object集合转换问题

getAllUser方法从Redis查询用户信息时,
返回的是Set<Object>类型,
需要转换成List<User>类型返回,
由于存入的类型一定是User,
所以Object一定能强转为User:

Set<Object> userObjects = zset.rangeByScore(ZSET_USER, min, max);
List<User> users = Lists.transform(new ArrayList<>(userObjects), object -> (User) object);

上面使用了Google Guava的Lists进行转换的,
需要在pom中增加如下依赖:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1.1-jre</version>
</dependency>

6.查看Redis数据

登录Redis服务端,
查看存储在zset_user中的数据,
并且输出其关联的id:

127.0.0.1:6379> zrange zset_user 0 -1 withscores
1) "{\"@class\":\"com.yuwen.spring.demo.entity.User\",\"id\":2,\"name\":\"tom\",\"birthday\":null,\"email\":null}"
2) "2"
3) "{\"@class\":\"com.yuwen.spring.demo.entity.User\",\"id\":3,\"name\":\"jack\",\"birthday\":null,\"email\":null}"
4) "3"
5) "{\"@class\":\"com.yuwen.spring.demo.entity.User\",\"id\":7,\"name\":\"sam\",\"birthday\":null,\"email\":null}"
6) "7"

可以看到输出的数据是能够看懂的,
携带其类名的JSON格式。

7.实体类User说明

Demo中使用的User.java源码如下:

package com.yuwen.spring.demo.entity;
import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    private static final long serialVersionUID = -3301999810945119126L;

    private Long id;

    private String name;

    private Date birthday;

    private String email;

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", birthday=" + birthday + ", email=" + email + "]";
    }
}

由于在RedisConfig.java中,
设置了RedisTemplate的value序列化方式为JSON,
JSON格式不要求实体类实现Serializable,
但是使用默认的JDK格式,
一定要实现序列化接口,
否则数据无法存储到Redis。

8.参考文章

springboot集成redis (Lettuce)
【深入浅出SpringBoot】RedisTemplate使用方法归纳

相关文章