当前位置:   article > 正文

SpringBoot整合Redis(Lettuce)_springboot lettuce

springboot lettuce

spingboot3.0系列示例代码采用3.1.0版本,jdk版本使用17+

Lettuce 简介:

Lettuce 是 Redis 的一款高级 Java 客户端,与 Jedis 并列成为最热门的客户端之一。

相比老牌 Jedis,Lettuce 属于后起之秀,不仅功能丰富,而且提供了很多新的功能特性,比如异步操作、响应式编程等等,同时还解决了 Jedis 中线程不安全的问题。

Lettuce 和 Jedis 一样,都是连接 Redis Server 的客户端程序。Jedis 在实现上是直连 Redis Server,多线程环境下非线程安全,除非使用连接池,为每个 Jedis 实例增加物理连接。 Lettuce 基于 Netty 的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全,满足多线程环境下的并发访问,同时它是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。(推荐使用)

工程实战

1.工程依赖 pom.xml 如下:

<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

  • spring-boot-starter-data-redis :在 Spring Boot 2.x 后底层不再是使用 Jedis ,而是换成了 Lettuce ,如图:

0

  • commons-pool2 : 用作 redis 连接池,如不引入启动会报错。
  • spring-session-data-redis : Spring Session 引入,用作共享 Session 。

2.配置文件 application.properties

server.port=8080 server.servlet.session.timeout=30m spring.application.name=spring-boot-redis # 使用了Spring Cache后,能指定spring.cache.type就手动指定一下, # 虽然它会自动去适配已有Cache的依赖,但先后顺序会对Redis使用有影响(JCache -> EhCache -> Redis -> Guava) spring.cache.type=REDIS spring.data.redis.host=127.0.0.1 spring.data.redis.port=6379 spring.data.redis.password=123456 # 连接超时时间(ms) spring.data.redis.timeout=10000 # Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0 spring.data.redis.database=0 # 连接池最大连接数(使用负值表示没有限制) 默认 8 spring.data.redis.lettuce.pool.max-active=100 # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1 spring.data.redis.lettuce.pool.max-wait=-1 # 连接池中的最大空闲连接 默认 8 spring.data.redis.lettuce.pool.max-idle=8 # 连接池中的最小空闲连接 默认 0 spring.data.redis.lettuce.pool.min-idle=0

【注意:redis密码123456】

上一章内容 redis根目录下 redis.windows.conf 文件:修改 requirepass 123456,并启动;

0

3.RedisTemplate 使用方式

(1)创建实体类 User.java com.lfz.redis.entity.User.java

package com.lfz.redis.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @AllArgsConstructor @NoArgsConstructor public class User implements Serializable { private static final long serialVersionUID = 662692455422902539L; private Long id; private String name; private int age; }

(2)自定义 RedisTemplate

默认情况下的模板只能支持 RedisTemplate ,也就是只能存入字符串,这在开发中是不友好的,

所以自定义模板是很有必要的,当自定义了模板又想使用 String 存储这时候就可以使用 StringRedisTemplate 的方式,它们并不冲突,

添加配置类 RedisCacheConfig.java com.lfz.redis.config.RedisCacheConfig.java

package com.lfz.redis.config; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.io.Serializable; @Configuration public class RedisCacheConfig { @Bean public RedisTemplate<String, Object> redisCacheTemplate(LettuceConnectionFactory lettuceConnectionFactory) { RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); // 设置key序列化方式string,RedisSerializer.string() 等价于 new StringRedisSerializer() redisTemplate.setKeySerializer(RedisSerializer.string()); // 设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化,RedisSerializer.json() 等价于 new GenericJackson2JsonRedisSerializer() redisTemplate.setValueSerializer(RedisSerializer.json()); // 设置hash的key的序列化方式 redisTemplate.setHashKeySerializer(RedisSerializer.string()); // 设置hash的value的序列化方式 redisTemplate.setHashValueSerializer(RedisSerializer.json()); // 使配置生效 redisTemplate.afterPropertiesSet(); return redisTemplate; } }

(3)测试接口 UserController.java com.lfz.redis.controller.UserController.java

package com.lfz.redis.controller; import com.lfz.redis.entity.User; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController @Slf4j public class UserController { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired RedisTemplate<String, Object> redisCacheTemplate; @GetMapping("/test") public Map<String,Object> test() { Map<String,Object> map=new HashMap(); //存储String类型数据 stringRedisTemplate.opsForValue().set("name", "bigger"); //获取String类型数据 map.put("name",stringRedisTemplate.opsForValue().get("name")); log.info("当前获取对象:{}",stringRedisTemplate.opsForValue().get("name")); //存储User实体类型数据 redisCacheTemplate.opsForValue().set("userinfo", new User(1L, "bigger", 17)); //获取User实体类型数据 User user = (User) redisCacheTemplate.opsForValue().get("userinfo"); map.put("userinfo",stringRedisTemplate.opsForValue().get("userinfo")); log.info("当前获取对象:{}", user); //存储List泛型集合类型数据 List<User> users=new ArrayList<>(); users.add(new User(2L,"张无忌",34)); users.add(new User(3L,"周芷若",28)); redisCacheTemplate.opsForValue().set("userlist",users); //获取List泛型集合类型数据 List<User> userlist=(List<User>)redisCacheTemplate.opsForValue().get("userlist"); map.put("userlist",stringRedisTemplate.opsForValue().get("userlist")); log.info("当前获取对象集合:{}", userlist); return map; } }

(4)测试

启动服务,打开浏览器访问链接:http://localhost:8080/test ,

查看控制台日志打印,如下:

0

查看页面,如下:

0

Redis可视化工具,如下:

0

测试成功

4.使用 Spring Cache 集成 Redis

(1)Spring Cache 特点

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

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

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

(2) 定义接口 UserService.java com.lfz.redis.service.UserService.java

package com.lfz.redis.service; import com.lfz.redis.entity.User; public interface UserService { User save(User user); User get(Long id); void delete(Long id); }

(3)接口实现 UserServiceImpl.java com.lfz.redis.service.impl.UserServiceImpl.java

package com.lfz.redis.service.impl; import com.lfz.redis.entity.User; import com.lfz.redis.service.UserService; import lombok.extern.slf4j.Slf4j; 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; @Service @Slf4j public class UserServiceImpl implements UserService { private static final Map<Long, User> USER_MAP = new HashMap<>(); static { USER_MAP.put(1L, new User(1L, "张无忌", 18)); USER_MAP.put(2L, new User(2L, "周芷若", 19)); USER_MAP.put(3L, new User(3L, "赵敏", 20)); } @CachePut(value = "user", key = "#user.id") @Override public User save(User user) { USER_MAP.put(user.getId(), user); log.info("进入 save 方法,当前存储对象:{}", user); return user; } @Cacheable(value = "user", key = "#id") @Override public User get(Long id) { log.info("进入 get 方法,当前获取对象:{}", USER_MAP.get(id)); return USER_MAP.get(id); } @CacheEvict(value = "user", key = "#id") @Override public void delete(Long id) { USER_MAP.remove(id); log.info("进入 delete 方法,删除成功"); } }

为了方便演示数据库操作,直接定义了一个 Map USER_MAP 集合模拟数据库数据,

这里的核心就是三个注解 @Cacheable 、 @CachePut 、 @CacheEvict 。

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

  • key: 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 (@Cacheable(value="user",key="#userName"))
  • value: 缓存的名称,必须指定至少一个(如:@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: 同上

@CacheEvict  根据条件对缓存进行清空

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

(4)开启 Spring Session

主类需增加注解 @EnableCaching 开启 Spring Session

0

(5)增加测试接口 com.lfz.redis.controller/UserController.java

@Autowired UserService userService; @GetMapping("/test1") public void test1() { User user = userService.save(new User(4L, "小昭", 35)); log.info("当前 save 对象:{}", user); user = userService.get(1L); log.info("当前 get 对象:{}", user); userService.delete(5L); }

(6)测试

启动服务,打开浏览器访问链接:http://localhost:8080/test1 ,刷新页面,控制台日志打印如下

0

再次刷新页面,查看控制台日志:

0

可以看到增删改查中,查询是没有日志输出的,因为它直接从缓存中获取的数据,

而添加、修改、删除都是会进入 UserServiceImpl 的方法内执行具体的业务代码【修改缓存数据】。

5.Session 共享

(1)Spring Session 简介

Spring Session 提供了一套创建和管理 Servlet HttpSession 的方案。

Spring Session 提供了集群 Session(Clustered Sessions)功能,默认采用外置的 Redis 来存储 Session 数据,以此来解决 Session 共享的问题。

(2)主类需增加注解 @EnableRedisHttpSession 设置 Session 失效时间

0

maxInactiveIntervalInSeconds: 设置 Session 失效时间,使用 Spring Session 之后,原 Spring Boot 配置文件application.properties 中的 server.session.timeout 属性不再生效。

(3)增加测试接口 com.lfz.redis.controller/UserController.java

@GetMapping("/getTestUrl") public String getSessionId(HttpServletRequest request) { String url = (String) request.getSession().getAttribute("url"); if (StringUtils.isEmpty(url)) { request.getSession().setAttribute("url", "http://www.baidu.com"); } log.info("获取session内容为: {}", request.getSession().getAttribute("url")); return request.getRequestedSessionId(); }

启动服务,打开浏览器访问链接:http://localhost:8080/getTestUrl ,查看 Redis 当前存储内容,如下图:

0

0

6 如何在多台服务中共享 Session

按照上面的步骤在另一个项目中再次配置一次,启动后自动就进行了 Session 共享。

有道云:有道云笔记

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/923169
推荐阅读
相关标签
  

闽ICP备14008679号