spring boot redis 缓存(cache)集成


Spring Boot 集成教程


概述

本文介绍spring boot项目集成redis缓存的过程。

redis是一个开源的内存NOSQL数据库,在web开发中主要被用于数据缓存。一般在高并发的情况下,web服务器接受访问时,直接从数据库加载是慢的,需要把常用数据缓存到redis中,提高加载速度和并发能力。

项目内容

创建一个spring boot项目,配置redis各相关 bean,实现几个接口,通过两种方式测试redis缓存:

  • 以注解方式自动缓存
  • RedisTemplate手动访问redis服务器

要求

  • 安装redis服务器,参考官网文档,如没有linux系统可虚拟机安装
  • JDK1.8或更新版本
  • Eclipse开发环境

如没有开发环境,可参考前面章节:[spring boot 开发环境搭建(Eclipse)]。

项目创建

创建spring boot项目

打开Eclipse,创建spring boot的spring starter project项目,选择菜单:File > New > Project ...,弹出对话框,选择:Spring Boot > Spring Starter Project,在配置依赖时,勾选webredis,完成项目创建。

项目依赖

需要用到commons-pool2库,在pom.xml中添加依赖

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

项目配置

application.properties文件中配置redis服务器的连接

## REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.0.99
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0

代码实现

项目目录结构如下图,我们添加了几个类,下面将详细介绍。

Redis Java配置(RedisConfig.java)

首先使用@EnableCaching开启以注解方式使用缓存。

然后配置redis相关的bean

  • RedisTemplate - 访问redis的bean,用于手动访问redis服务器
  • 缓存管理器 - 注解方式使用缓存的配置
  • KeyGenerator - 自定义缓存key的生成
  • Json序列化 - Json对象被缓存时的序列化
/**
 * @description redis配置  配置序列化方式以及缓存管理器
 */
@EnableCaching // 开启缓存
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {

    /**
     * 配置自定义redisTemplate
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setValueSerializer(jackson2JsonRedisSerializer());
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    /**
     * json序列化
     * @return
     */
    @Bean
    public RedisSerializer<Object> jackson2JsonRedisSerializer() {
        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);

        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);
        return serializer;
    }

    /**
     * 配置缓存管理器
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        // 设置缓存的默认过期时间,也是使用Duration设置
        config = config.entryTtl(Duration.ofMinutes(1))
                // 设置 key为string序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                // 设置value为json序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()))
                // 不缓存空值
                .disableCachingNullValues();

        // 设置一个初始化的缓存空间set集合
        Set<String> cacheNames = new HashSet<>();
        cacheNames.add("timeGroup");
        cacheNames.add("user");

        // 对每个缓存空间应用不同的配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        configMap.put("timeGroup", config);
        configMap.put("user", config.entryTtl(Duration.ofSeconds(120)));

        // 使用自定义的缓存配置初始化一个cacheManager
        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
                // 一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
                .initialCacheNames(cacheNames)
                .withInitialCacheConfigurations(configMap)
                .build();
        return cacheManager;
    }

    /**
     * 缓存的key是 包名+方法名+参数列表
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append("::" + method.getName() + ":");
            for (Object obj : objects) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }

}

添加实体类 User


public class User {
    private long id;
    private String nickname;
    private String mobile;

    @JsonProperty(access = Access.WRITE_ONLY) //在输出的Json数据中隐藏密码,只能输入不输出
    private String password;
    private String role;

    public User(long id, String nickname, String mobile, String password, String role) {
        this.id = id;
        this.nickname = nickname;
        this.mobile = mobile;
        this.password = password;
        this.role = role;
    }

    public User() {
        super();
    }

    public String getNickname() {
        return nickname;
    }
    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getMobile() {
        return mobile;
    }
    public void setMobile(String mobile) {
        this.mobile = mobile;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getRole() {
        return role;
    }
    public void setRole(String role) {
        this.role = role;
    }
}

常用的缓存注解

  • @Cacheable - 表明对应方法的返回结果可以被缓存,首次调用后,下次就从缓存中读取结果,方法不会再被执行了。
  • @CachePut - 更新缓存,方法每次都会执行
  • @CacheEvict - 清除缓存,方法每次都会执行

添加User的服务层

因为主要的业务逻辑在服务层实现,一般会把缓存注解加在服务层的方法上。

下面几个服务层的方法会加缓存注解:

  • getUserById - 方法的返回结果会被缓存到redis,使用注解@Cacheable
  • updateUserNickname - 原始数据被更新了,废弃缓存数据,使用注解@CacheEvict

UserSevice.java 接口

public interface UserService {

    public User getUserById(long userId);
    public User updateUserNickname(long userId, String nickname);
}

UserServiceImpl.java 实现类


@Service("userService")
public class UserServiceImpl implements UserService {

    private static final org.slf4j.Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    private User user = new User(1l, "abc1", "13512345678", "123456", "role-user");

    @Cacheable(value = "user", key= "#userId")
    @Override
    public User getUserById(long userId) {

        log.info("加载用户信息");
        return user;
    }

    @CacheEvict(value = "user", key= "#userId")
    @Override
    public User updateUserNickname(long userId, String nickname) {

        user.setNickname(nickname);

        return user;
    }
}

添加User的控制层


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

    // 注入service类
    @Resource
    private UserService userService;

    // 注入RedisTemplate
    @Resource
    private RedisTemplate<String, Object> redis;

    // 读取用户信息,测试缓存使用:除了首次读取,接下来都应该从缓存中读取
    @RequestMapping(value="{id}", method=RequestMethod.GET, produces="application/json")
    public User getUser(@PathVariable long id) throws Exception {

        User user = this.userService.getUserById(id);

        return user;
    }

    // 修改用户信息,测试删除缓存
    @RequestMapping(value = "/{id}/change-nick", method = RequestMethod.POST, produces="application/json")
    public User changeNickname(@PathVariable long id) throws Exception{

        String nick = "abc-" + Math.random();
        User user = this.userService.updateUserNickname(id, nick);

        return user;
    }

    // 使用RedisTemplate访问redis服务器
    @RequestMapping(value="/redis", method=RequestMethod.GET, produces="application/json")
    public String redis() throws Exception {

        // 设置键"project-name",值"qikegu-springboot-redis-demo"
        redis.opsForValue().set("project-name", "qikegu-springboot-redis-demo");
        String value = (String) redis.opsForValue().get("project-name");

        return value;
    }
}

运行

Eclipse左侧,在项目根目录上点击鼠标右键弹出菜单,选择:run as -> spring boot app运行程序。 打开Postman访问接口,
同时监控redis服务器。

监控redis服务器,使用redis-cli命令连上服务器,然后使用monitor命令开始监控:

运行结果如下:

获取用户信息

redis中的数据,可以看到数据通过SET指令保存进redis了

多次获取用户信息,可以看到通过GET指令从redis中读取缓存

修改用户信息

redis中的缓存被删除了

测试使用RedisTemplate访问redis服务器

redis中的数据变化

总结

完整代码

原文地址:https://www.cnblogs.com/haibianren/p/11577680.html

时间: 2024-08-08 10:12:57

spring boot redis 缓存(cache)集成的相关文章

使用maven简单搭建Spring mvc + redis缓存

注:此文参考并整合了网上的文章 <spring缓存机制>:http://blog.csdn.net/sidongxue2/article/details/30516141 <配置 Spring4.0 注解Cache+Redis缓存>:http://blog.csdn.net/ouyhong123/article/details/52162951 <spring整合redis缓存,以注解(@Cacheable.@CachePut.@CacheEvict)形式使用>: ht

spring boot 1.5.4 集成devTools(五)

上一篇:spring boot 1.5.4 整合JSP(四) 1.1    Spring Boot集成devTools spring boot集成devTools源码:https://git.oschina.net/wyait/springboot1.5.4.git 实现步骤: Eclipse Project 必须开启了Build Automatically,如果关闭了自动编译的功能,热部署无效. 1. pom引入devTools依赖和插件配置 <!-- devtools--> <dep

spring boot 1.5.4 集成spring-Data-JPA(七)

上一篇:springboot 1.5.4 集成JdbcTemplate(六) 1      Spring Boot使用Spring-Data-JPA访问数据库 spring boot整合jdbcTemplate项目源码: https://git.oschina.net/wyait/springboot1.5.4.git 1.1  Sping data JPA简介 关于Spring Data jpa这里就不详细做说明,只简单的介绍一下: 由于Spring-data-jpa依赖于Hibernate.

spring boot 1.5.4 集成Swagger2构建Restful API(十八)

上一篇博客地址:springboot 1.5.4 整合rabbitMQ(十七) 1      Spring Boot集成Swagger2构建RESTful API文档 1.1  Swagger2简介 Swagger2官网:http://swagger.io/ 由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会

spring boot + redis 实现session共享

这次带来的是spring boot + redis 实现session共享的教程. 在spring boot的文档中,告诉我们添加@EnableRedisHttpSession来开启spring session支持,配置如下: @Configuration @EnableRedisHttpSession public class RedisSessionConfig { } 而@EnableRedisHttpSession这个注解是由spring-session-data-redis提供的,所以

spring boot 1.5.4 集成JdbcTemplate(六)

上一篇:spring boot 1.5.4 集成devTools(五) Spring Boot使用JdbcTemplate访问数据库 spring boot整合jdbcTemplate项目源码: https://git.oschina.net/wyait/springboot1.5.4.git Spring的JdbcTemplate是自动配置的,你可以直接使用@Autowired来注入到你自己的bean中来使用. ①   导入jdbcTemplate和mysql(默认版本:5.1.42)数据库依

Spring Boot微服务如何集成fescar解决分布式事务?

什么是fescar? 关于fescar的详细介绍,请参阅fescar wiki. 传统的2PC提交协议,会持有一个全局性的锁,所有局部事务预提交成功后一起提交,或有一个局部事务预提交失败后一起回滚,最后释放全局锁.锁持有的时间较长,会对并发造成较大的影响,死锁的风险也较高. fescar的创新之处在于,每个局部事务执行完立即提交,释放本地锁:它会去解析你代码中的sql,从数据库中获得事务提交前的事务资源即数据,存放到undo_log中,全局事务协调器在回滚的时候直接使用undo_log中的数据覆

Spring Boot(八)集成Spring Cache 和 Redis

在Spring Boot中添加spring-boot-starter-data-redis依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 在application.properties中指定redis服务器IP.端口和密码.

Spring Boot(六)集成 MyBatis 操作 MySQL 8

一.简介 1.1 MyBatis介绍 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC代码和手动设置参数以及获取结果集. 1.2 MyBatis发展史 MyBatis 原本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis ,2013年11月迁移到Github. ### 1.3 MyBatis和H