spring boot 使用Spring Cache集成Redis

Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 Redis),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果。

特点

具备相当的好的灵活性,不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业缓存例如 EHCache、Redis、Guava 的集成。

  • 基于 annotation 即可使得现有代码支持缓存
  • 开箱即用 Out-Of-The-Box,不用安装和部署额外第三方组件即可使用缓存
  • 支持 Spring Express Language,能使用对象的任何属性或者方法来定义缓存的 key 和 condition
  • 支持 AspectJ,并通过其实现任何方法的缓存支持
  • 支持自定义 key 和自定义缓存管理者,具有相当的灵活性和扩展性

使用前后

下面针对Spring Cache使用前后给出了伪代码部分,具体中也许比这要更加复杂,但是Spring Cache都可以很好的应对

使用前

我们需要硬编码,如果切换Cache Client还需要修改代码,耦合度高,不易于维护

public String get(String key) {
    String value = userMapper.selectById(key);
    if (value != null) {
        cache.put(key,value);
    }
    return value;
}

使用后

基于Spring Cache注解,缓存由开发者自己配置,但不用参与到具体编码

@Cacheable(value = "user", key = "#key")
public String get(String key) {
    return userMapper.selectById(key);
}

添加依赖

在 pom.xml 中添加 spring-boot-starter-data-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>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

属性配置

在 application.properties 文件中配置如下内容,由于Spring Boot2.x 的改动,连接池相关配置需要通过spring.redis.lettuce.pool 或者 spring.redis.jedis.pool 进行配置了。使用了Spring Cache后,能指定spring.cache.type就手动指定一下,虽然它会自动去适配已有Cache的依赖,但先后顺序会对Redis使用有影响(JCache -> EhCache -> Redis -> Guava

spring.redis.host=localhost
spring.redis.password=battcn
# 一般来说是不用配置的,Spring Cache 会根据依赖的包自行装配
spring.cache.type=redis
# 连接超时时间(毫秒)
spring.redis.timeout=10000
# Redis默认情况下有16个分片,这里配置具体使用的分片
spring.redis.database=0
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0

具体编码

实体类

创建一个User类,目的是为了模拟对象存储

package com.battcn.entity;

import java.io.Serializable;

/**
 * @author Levin
 * @since 2018/5/11 0007
 */
public class User implements Serializable {

    private static final long serialVersionUID = 8655851615465363473L;
    private Long id;
    private String username;
    private String password;
    // TODO  省略get set
}

定义接口

package com.battcn.service;

import com.battcn.entity.User;

/**
 * @author Levin
 * @since 2018/5/11 0011
 */
public interface UserService {

    /**
     * 删除
     *
     * @param user 用户对象
     * @return 操作结果
     */
    User saveOrUpdate(User user);

    /**
     * 添加
     *
     * @param id key值
     * @return 返回结果
     */
    User get(Long id);

    /**
     * 删除
     *
     * @param id key值
     */
    void delete(Long id);
}

###实现类

为了方便演示数据库操作,直接定义了一个Map<Long, User> DATABASES,这里的核心就是@Cacheable@CachePut@CacheEvict 三个注解

package com.battcn.service.impl;

import com.battcn.entity.User;
import com.battcn.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Levin
 * @since 2018/5/11 0011
 */
@Service
public class UserServiceImpl implements UserService {

    private static final Map<Long, User> DATABASES = new HashMap<>();

    static {
        DATABASES.put(1L, new User(1L, "u1", "p1"));
        DATABASES.put(2L, new User(2L, "u2", "p2"));
        DATABASES.put(3L, new User(3L, "u3", "p3"));
    }


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

    @Cacheable(value = "user", key = "#id")// 根据方法的请求参数对其结果进行缓存
    @Override
    public User get(Long id) {
        // TODO 我们就假设它是从数据库读取出来的
        log.info("进入 get 方法");
        return DATABASES.get(id);
    }

    @CachePut(value = "user", key = "#user.id")// 根据方法的请求参数对其结果进行缓存
    @Override
    public User saveOrUpdate(User user) {
        DATABASES.put(user.getId(), user);
        log.info("进入 saveOrUpdate 方法");
        return user;
    }

    @CacheEvict(value = "user", key = "#id")// 根据条件对缓存进行清空
    @Override
    public void delete(Long id) {
        DATABASES.remove(id);
        log.info("进入 delete 方法");
    }
}

主函数

@EnableCaching 必须要加,否则spring-data-cache相关注解不会生效...

package com.battcn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

/**
 * @author Levin
 */
@SpringBootApplication
@EnableCaching
public class Chapter9Application {

    public static void main(String[] args) {
        SpringApplication.run(Chapter9Application.class, args);
    }

}

测试

完成准备事项后,编写一个junit测试类来检验代码的正确性,有很多人质疑过Redis线程安全性,故下面也提供了响应的测试案例,如有疑问欢迎指正

package com.battcn;

import com.battcn.entity.User;
import com.battcn.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author Levin
 * @since 2018/5/10 0010
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter9ApplicationTest {

    private static final Logger log = LoggerFactory.getLogger(Chapter9ApplicationTest.class);


    @Autowired
    private UserService userService;


    @Test
    public void get() {
        final User user = userService.saveOrUpdate(new User(5L, "u5", "p5"));
        log.info("[saveOrUpdate] - [{}]", user);
        final User user1 = userService.get(5L);
        log.info("[get] - [{}]", user1);
        userService.delete(5L);
    }
}

启动测试类,结果和我们期望的一致,可以看到增删改查中,查询是没有日志输出的,因为它直接从缓存中获取的数据,而添加、修改、删除都是会进入方法内执行具体的业务代码,然后通过切面去删除掉Redis中的缓存数据。其中 # 号代表这是一个 SpEL 表达式,此表达式可以遍历方法的参数对象,具体语法可以参考 Spring 的相关文档手册。

2018-05-14 09:20:55.303  INFO 21176 --- [           main] com.battcn.service.impl.UserServiceImpl  : 进入 saveOrUpdate 方法
2018-05-14 09:20:55.582  INFO 21176 --- [           main] io.lettuce.core.EpollProvider            : Starting without optional epoll library
2018-05-14 09:20:55.584  INFO 21176 --- [           main] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
2018-05-14 09:20:56.316  INFO 21176 --- [           main] com.battcn.Chapter9ApplicationTest       : [saveOrUpdate] - [User{id=5, username='u5', password='p5'}]
2018-05-14 09:20:56.320  INFO 21176 --- [           main] com.battcn.Chapter9ApplicationTest       : [get] - [User{id=5, username='u5', password='p5'}]
2018-05-14 09:20:56.322  INFO 21176 --- [           main] com.battcn.service.impl.UserServiceImpl  : 进入 delete 方法

其它类型

下列的就是Redis其它类型所对应的操作方式

  • opsForValue: 对应 String(字符串)
  • opsForZSet: 对应 ZSet(有序集合)
  • opsForHash: 对应 Hash(哈希)
  • opsForList: 对应 List(列表)
  • opsForSet: 对应 Set(集合)
  • opsForGeo: 对应 GEO(地理位置)

根据条件操作缓存

根据条件操作缓存内容并不影响数据库操作,条件表达式返回一个布尔值,true/false,当条件为true,则进行缓存操作,否则直接调用方法执行的返回结果。

  • 长度: @CachePut(value = "user", key = "#user.id",condition = "#user.username.length() < 10") 只缓存用户名长度少于10的数据
  • 大小: @Cacheable(value = "user", key = "#id",condition = "#id < 10") 只缓存ID小于10的数据
  • 组合: @Cacheable(value="user",key="#user.username.concat(##user.password)")
  • 提前操作: @CacheEvict(value="user",allEntries=true,beforeInvocation=true) 加上beforeInvocation=true后,不管内部是否报错,缓存都将被清除,默认情况为false

注解介绍

@Cacheable(根据方法的请求参数对其结果进行缓存)

  • key: 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合(如:@Cacheable(value="user",key="#userName")
  • value: 缓存的名称,在 Spring 配置文件中定义,必须指定至少一个(如:@Cacheable(value="user") 或者
    @Cacheable(value={"user1","use2"})
  • condition: 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存(如:@Cacheable(value = "user", key = "#id",condition = "#id < 10")

@CachePut(根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用)

  • key: 同上
  • value: 同上
  • condition: 同上

@CachEvict(根据条件对缓存进行清空)

  • key: 同上
  • value: 同上
  • condition: 同上
  • allEntries: 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存(如:@CacheEvict(value = "user", key = "#id", allEntries = true)
  • beforeInvocation: 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存(如:@CacheEvict(value = "user", key = "#id", beforeInvocation = true)

总结

spring-cache文档: https://docs.spring.io/spring/docs/5.0.5.RELEASE/spring-framework-reference/integration.html#cache-introduction
spring-data-redis文档: https://docs.spring.io/spring-data/redis/docs/2.0.1.RELEASE/reference/html/#new-in-2.0.0
Redis 文档: https://redis.io/documentation
Redis 中文文档: http://www.redis.cn/commands.html

目前很多大佬都写过关于 SpringBoot 的教程了,如有雷同,请多多包涵,本教程基于最新的 spring-boot-starter-parent:2.0.1.RELEASE编写,包括新版本的特性都会一起介绍...

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Spring Boot集成Redis可以通过以下步骤实现: 1. 添加Redis依赖:在Spring Boot项目的pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 2. 配置Redis连接信息:在application.properties文件中添加以下配置信息: ``` spring.redis.host=redis服务器IP spring.redis.port=redis服务器端口号 spring.redis.password=redis密码 ``` 3. 创建RedisTemplate:在Java代码中创建RedisTemplate对象,并注入到需要使用Redis的类中。 ``` @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); redisTemplate.afterPropertiesSet(); return redisTemplate; } } ``` 4. 使用RedisTemplate操作Redis:通过RedisTemplate对象的方法,可以进行各种Redis操作,如set、get、delete等。 以上是Spring Boot集成Redis的基本步骤,具体实现还需根据具体需求进行配置和调整。 ### 回答2: Spring Boot是一个基于Spring框架的快速开发框架,它提供了简化的配置和开箱即用的功能,使得我们可以快速构建和部署应用程序。而Redis是一个高性能的键值对存储数据库,它常被用于缓存和数据存储。 在Spring Boot集成Redis,首先需要引入相关的依赖。可以通过Maven或Gradle来引入spring-boot-starter-data-redis依赖,该依赖会自动引入Redis相关的配置和依赖库。 然后,在配置文件中添加Redis的连接信息。在application.properties或application.yml中,可以配置Redis的主机地址、端口号、密码等信息。 接下来,在需要使用Redis的地方,可以使用@Autowired注解来注入RedisTemplate对象。RedisTemplate是Spring提供的操作Redis的模板类,它封装了常用的操作方法。 使用RedisTemplate,可以通过调用其对应的方法来操作Redis数据库,比如设置键值对、获取键值对、设置过期时间等。 除了RedisTemplate,Spring Boot还提供了RedisCacheManager类用于缓存管理,它可以通过注解@Configuration和@EnableCaching来启用缓存功能。在需要缓存的方法上使用@Cacheable注解,就可以将方法的返回值缓存到Redis中,下次调用时可以直接从缓存中获取,提高了性能。 总的来说,集成RedisSpring Boot中,只需要引入依赖、配置连接信息,然后通过RedisTemplate操作Redis数据库,或使用RedisCacheManager进行数据缓存管理就可以了。这样可以简化我们与Redis的交互,提高开发效率和应用性能。 ### 回答3: 在Spring Boot中,集成Redis可以通过以下步骤实现: 1. 在pom.xml文件中添加Redis的依赖库: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 2. 在application.properties或application.yaml文件中配置Redis连接信息: ```properties spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password= ``` 3. 创建一个Redis配置类,用于配置Redis连接工厂: ```java @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Bean @Override public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { // 生成缓存的key,可以根据实际需求定制 return ""; } }; } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(connectionFactory); // 设置value的序列化方式 redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // 设置key的序列化方式 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } } ``` 4. 在需要使用Redis的类中,通过注入RedisTemplate来操作Redis: ```java @Autowired private RedisTemplate<String, Object> redisTemplate; public void cacheData(String key, Object value) { redisTemplate.opsForValue().set(key, value); } public Object getData(String key) { return redisTemplate.opsForValue().get(key); } ``` 通过以上步骤,我们就成功在Spring Boot集成Redis,可以方便地使用Redis进行缓存、存储和读取数据。在配置Redis时,我们需要根据实际情况修改host、port和password等配置项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘彦青-Yannis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值