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中添加依赖

  1. <dependency>
  2. <groupId>org.apache.commons</groupId>
  3. <artifactId>commons-pool2</artifactId>
  4. </dependency>

项目配置

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

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

代码实现

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

Redis Java配置(RedisConfig.java)

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

然后配置redis相关的bean

  • RedisTemplate - 访问redis的bean,用于手动访问redis服务器
  • 缓存管理器 - 注解方式使用缓存的配置
  • KeyGenerator - 自定义缓存key的生成
  • Json序列化 - Json对象被缓存时的序列化
  1. /**
  2. * @description redis配置 配置序列化方式以及缓存管理器
  3. */
  4. @EnableCaching // 开启缓存
  5. @Configuration
  6. @AutoConfigureAfter(RedisAutoConfiguration.class)
  7. public class RedisConfig {
  8. /**
  9. * 配置自定义redisTemplate
  10. *
  11. * @param connectionFactory
  12. * @return
  13. */
  14. @Bean
  15. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
  16. RedisTemplate<String, Object> template = new RedisTemplate<>();
  17. template.setConnectionFactory(connectionFactory);
  18. template.setValueSerializer(jackson2JsonRedisSerializer());
  19. //使用StringRedisSerializer来序列化和反序列化redis的key值
  20. template.setKeySerializer(new StringRedisSerializer());
  21. template.setHashKeySerializer(new StringRedisSerializer());
  22. template.setHashValueSerializer(jackson2JsonRedisSerializer());
  23. template.afterPropertiesSet();
  24. return template;
  25. }
  26. /**
  27. * json序列化
  28. * @return
  29. */
  30. @Bean
  31. public RedisSerializer<Object> jackson2JsonRedisSerializer() {
  32. //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
  33. Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
  34. ObjectMapper mapper = new ObjectMapper();
  35. mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  36. mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  37. serializer.setObjectMapper(mapper);
  38. return serializer;
  39. }
  40. /**
  41. * 配置缓存管理器
  42. * @param redisConnectionFactory
  43. * @return
  44. */
  45. @Bean
  46. public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
  47. // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
  48. RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
  49. // 设置缓存的默认过期时间,也是使用Duration设置
  50. config = config.entryTtl(Duration.ofMinutes(1))
  51. // 设置 key为string序列化
  52. .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
  53. // 设置value为json序列化
  54. .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()))
  55. // 不缓存空值
  56. .disableCachingNullValues();
  57. // 设置一个初始化的缓存空间set集合
  58. Set<String> cacheNames = new HashSet<>();
  59. cacheNames.add("timeGroup");
  60. cacheNames.add("user");
  61. // 对每个缓存空间应用不同的配置
  62. Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
  63. configMap.put("timeGroup", config);
  64. configMap.put("user", config.entryTtl(Duration.ofSeconds(120)));
  65. // 使用自定义的缓存配置初始化一个cacheManager
  66. RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
  67. // 一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
  68. .initialCacheNames(cacheNames)
  69. .withInitialCacheConfigurations(configMap)
  70. .build();
  71. return cacheManager;
  72. }
  73. /**
  74. * 缓存的key是 包名+方法名+参数列表
  75. */
  76. @Bean
  77. public KeyGenerator keyGenerator() {
  78. return (target, method, objects) -> {
  79. StringBuilder sb = new StringBuilder();
  80. sb.append(target.getClass().getName());
  81. sb.append("::" + method.getName() + ":");
  82. for (Object obj : objects) {
  83. sb.append(obj.toString());
  84. }
  85. return sb.toString();
  86. };
  87. }
  88. }

添加实体类 User


  1. public class User {
  2. private long id;
  3. private String nickname;
  4. private String mobile;
  5. @JsonProperty(access = Access.WRITE_ONLY) //在输出的Json数据中隐藏密码,只能输入不输出
  6. private String password;
  7. private String role;
  8. public User(long id, String nickname, String mobile, String password, String role) {
  9. this.id = id;
  10. this.nickname = nickname;
  11. this.mobile = mobile;
  12. this.password = password;
  13. this.role = role;
  14. }
  15. public User() {
  16. super();
  17. }
  18. public String getNickname() {
  19. return nickname;
  20. }
  21. public void setNickname(String nickname) {
  22. this.nickname = nickname;
  23. }
  24. public long getId() {
  25. return id;
  26. }
  27. public void setId(long id) {
  28. this.id = id;
  29. }
  30. public String getMobile() {
  31. return mobile;
  32. }
  33. public void setMobile(String mobile) {
  34. this.mobile = mobile;
  35. }
  36. public String getPassword() {
  37. return password;
  38. }
  39. public void setPassword(String password) {
  40. this.password = password;
  41. }
  42. public String getRole() {
  43. return role;
  44. }
  45. public void setRole(String role) {
  46. this.role = role;
  47. }
  48. }

常用的缓存注解

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

添加User的服务层

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

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

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

UserSevice.java 接口

  1. public interface UserService {
  2. public User getUserById(long userId);
  3. public User updateUserNickname(long userId, String nickname);
  4. }

UserServiceImpl.java 实现类


  1. @Service("userService")
  2. public class UserServiceImpl implements UserService {
  3. private static final org.slf4j.Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
  4. private User user = new User(1l, "abc1", "13512345678", "123456", "role-user");
  5. @Cacheable(value = "user", key= "#userId")
  6. @Override
  7. public User getUserById(long userId) {
  8. log.info("加载用户信息");
  9. return user;
  10. }
  11. @CacheEvict(value = "user", key= "#userId")
  12. @Override
  13. public User updateUserNickname(long userId, String nickname) {
  14. user.setNickname(nickname);
  15. return user;
  16. }
  17. }

添加User的控制层


  1. @RestController
  2. @EnableAutoConfiguration
  3. @RequestMapping("/user")
  4. public class UserController {
  5. // 注入service类
  6. @Resource
  7. private UserService userService;
  8. // 注入RedisTemplate
  9. @Resource
  10. private RedisTemplate<String, Object> redis;
  11. // 读取用户信息,测试缓存使用:除了首次读取,接下来都应该从缓存中读取
  12. @RequestMapping(value="{id}", method=RequestMethod.GET, produces="application/json")
  13. public User getUser(@PathVariable long id) throws Exception {
  14. User user = this.userService.getUserById(id);
  15. return user;
  16. }
  17. // 修改用户信息,测试删除缓存
  18. @RequestMapping(value = "/{id}/change-nick", method = RequestMethod.POST, produces="application/json")
  19. public User changeNickname(@PathVariable long id) throws Exception{
  20. String nick = "abc-" + Math.random();
  21. User user = this.userService.updateUserNickname(id, nick);
  22. return user;
  23. }
  24. // 使用RedisTemplate访问redis服务器
  25. @RequestMapping(value="/redis", method=RequestMethod.GET, produces="application/json")
  26. public String redis() throws Exception {
  27. // 设置键"project-name",值"qikegu-springboot-redis-demo"
  28. redis.opsForValue().set("project-name", "qikegu-springboot-redis-demo");
  29. String value = (String) redis.opsForValue().get("project-name");
  30. return value;
  31. }
  32. }

运行

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

同时监控redis服务器。

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

运行结果如下:

获取用户信息

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

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

修改用户信息

redis中的缓存被删除了

测试使用RedisTemplate访问redis服务器

redis中的数据变化

总结

完整代码

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

  1. spring boot redis缓存JedisPool使用

    spring boot redis缓存JedisPool使用 添加依赖pom.xml中添加如下依赖 <!-- Spring Boot Redis --> <dependency> ...

  2. spring boot redis缓存入门

    摘要: 原创出处 泥瓦匠BYSocket 下载工程 springboot-learning-example ,工程代码注解很详细.JeffLi1993/springboot-learning-exam ...

  3. Spring Boot Redis 集成配置(转)

    Spring Boot Redis 集成配置 .embody{ padding:10px 10px 10px; margin:0 -20px; border-bottom:solid 1px #ede ...

  4. Spring Boot 项目学习 (三) Spring Boot + Redis 搭建

    0 引言 本文主要介绍 Spring Boot 中 Redis 的配置和基本使用. 1 配置 Redis 1. 修改pom.xml,添加Redis依赖 <!-- Spring Boot Redi ...

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

    注:此文参考并整合了网上的文章 <spring缓存机制>:http://blog.csdn.net/sidongxue2/article/details/30516141 <配置 S ...

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

    什么是fescar? 关于fescar的详细介绍,请参阅fescar wiki. 传统的2PC提交协议,会持有一个全局性的锁,所有局部事务预提交成功后一起提交,或有一个局部事务预提交失败后一起回滚,最 ...

  7. spring boot + redis 实现session共享

    这次带来的是spring boot + redis 实现session共享的教程. 在spring boot的文档中,告诉我们添加@EnableRedisHttpSession来开启spring se ...

  8. Spring Boot 2.0 快速集成整合消息中间件 Kafka

    欢迎关注个人微信公众号: 小哈学Java, 每日推送 Java 领域干货文章,关注即免费无套路附送 100G 海量学习.面试资源哟!! 个人网站: https://www.exception.site ...

  9. Spring Boot与ActiveMQ的集成

    Spring Boot对JMS(Java Message Service,Java消息服务)也提供了自动配置的支持,其主要支持的JMS实现有ActiveMQ.Artemis等.本节中,将以Active ...

随机推荐

  1. jmeter之Xpath提取器

    首先创建线程组,添加http请求,具体的设置如图1所示: 图1 然后,再添加后置处理器中的XPath Extractor,具体的参数设置,以及表达式如图2: 图2 可以添加Debug PostProc ...

  2. windows制作动态链接库和使用二

    动态库的另一种制作方法: 不使用_declspec(dllexport)关键字,使用.def文件 //exportFun.def 文件名随意 EXPORT add @ //格式 函数名 @编号 < ...

  3. EXTjs开发————优雅的用extjs写一个柱状图

    简单的写法,extjs可以直接引用插件来写,这里将我发表在百度文库的文档简述下来,有兴趣也可以关注我的百度文库,ID:该用户已失踪. 主要部分的代码: $(document).ready(functi ...

  4. 连接mysql报错java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized...解决方法

    报错内容: java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents mo ...

  5. Xcode8.0+和最新的Xcode9.0beta安装Alcatraz插件

    1.安装Alcatraz 1.1终端中输入 rm -rf ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins/Alcatraz ...

  6. parameterType和resultType

    在MyBatis中,我们通过parameterType完成输入映射(指将值映射到sql语句的占位符中,值的类型与dao层响应方法的参数类型一致),通过resultType完成输出映射(从数据库中输出, ...

  7. [题解] LuoguP3768 简单的数学题

    Description 传送门 给一个整数\(n\),让你求 \[ \sum\limits_{i=1}^n \sum\limits_{j=1}^n ij\gcd(i,j) \] 对一个大质数\(p\) ...

  8. 六、Vue-Router:基础路由处理、路由提取成单独文件、路由嵌套、路由传参数、路由高亮、html5的history使用

    一.vue-router的安装 官网文档 [官网]:https://cn.vuejs.org/v2/guide/routing.html [router文档]:https://router.vuejs ...

  9. Git 的 4 个阶段的撤销更改

    虽然git诞生距今已有12年之久,网上各种关于git的介绍文章数不胜数,但是依然有很多人(包括我自己在内)对于它的功能不能完全掌握.以下的介绍只是基于我个人对于git的理解,并且可能生编硬造了一些不完 ...

  10. linux下操作oracle

    ps -ef|grep ora #查看oracle状态 lsnrctl status #查看监听的状态 lsnrctl start |stop |reload #启动|停止|重启 监听 登录oracl ...