Spring与Redis集成

1.引入RedisTemplate

据以前的情况,我们在Java中使用Redis时一般是使用Jedis来操作的,大致的一段代码如下所示

    @Overridepublic User findUserById(Integer id) {User user = null;Jedis jedis = null;try {jedis = jedisPool.getResource();String userStr = jedis.get("user_" + id); // 尝试获取数据if (userStr != null && !userStr.isEmpty()) { // 如果获取到有效数据,则转换后返回user = JSONObject.parseObject(userStr, User.class);} else {// 如果没有获取到数据,则查询数据库返回user = userMapper.findUserById(id);if (user != null) jedis.set("user_" + id, JSONObject.toJSONString(user)); // 设置到redis中}} finally {// 记得关闭Jedis,因为这里使用的是JedisPool,所以这里的关闭并不是直接关闭连接,而是释放,以供其他的业务使用if (jedis != null) jedis.close();}return user;}

上边的这样的一段代码其实是有些臃肿的,但是如果我们引入RedisTemplate,其实会简化不少。

  • maven 引入 spring-data-redis
  <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.9.0</version></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>2.2.13.RELEASE</version></dependency>
  • 将RedisTemplate 加入Bean容器中,让Spring进行管理。
  @Beanpublic RedisConnectionFactory redisConnectionFactory() {RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();redisStandaloneConfiguration.setHostName(host);redisStandaloneConfiguration.setPort(port);RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);return redisConnectionFactory;}@Beanpublic RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate redisTemplate = new RedisTemplate();redisTemplate.setConnectionFactory(redisConnectionFactory);//设置key值的序列化方式,默认是JDK的形式redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);return redisTemplate;}
  • 如果使用RedisTemplate的替换的话,会简洁很多。
  @Autowiredprivate RedisTemplate redisTemplate;@Overridepublic User findUserById(Integer id) {Object result = redisTemplate.opsForValue().get("user_" + id);if (result != null) return (User) result;User user = userMapper.findUserById(id);// 设置到redis中if (user != null) redisTemplate.opsForValue().set("user_" + id, user);return user;}
  • 大概看一下关于RedisTemplate的方法

看了以上的内容,可以看到引入了RedisTemplate其实已经很简洁了,但是明显还不够,下面我们将考虑引入 “注解”


2. 引入注解

  • 开启缓存 @EnableCaching
  
@Configuration  
@EnableCaching  
public class AppConfig {
...
} 
  • 引入@Cacheable,表示这个方法将会访问缓存,如果无法命中缓存的话,会将方法返回的值存入redis,假设有注解为 @Cacheable(value="user", key = "#id"),那么生成的key值为 user::{id},即如果id为1 那么生成的 key就是 user::1
@Override
@Cacheable(value="user", key = "#id")
// 这里返回的值会被存放到redis,key-value格式,其中生成的key值(假设id为1): user::1
public User findUserById(Integer id) {
User user = userMapper.findUserById(id);
return user;
}

但是这样还不够,因为Spring并不清楚缓存的方式是什么,这就涉及到CacheManager

  • 设置CacheManager,在AppConfig中加入以下内容
@Bean
public RedisConnectionFactory redisConnectionFactory() {RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();redisStandaloneConfiguration.setHostName(host); // 这里是redis的ipredisStandaloneConfiguration.setPort(port);// 这里是redis的端口// 自适应集群变化RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);return redisConnectionFactory;
}@Bean
public RedisCacheConfiguration redisCacheConfiguration() {RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));return redisCacheConfiguration;
}@Bean
public RedisCacheWriter redisCacheWriter(RedisConnectionFactory redisConnectionFactory) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
return redisCacheWriter;
}@Bean
public CacheManager cacheManager(RedisCacheWriter redisCacheWriter, RedisCacheConfiguration redisCacheConfiguration) {CacheManager cacheManager = new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);((RedisCacheManager) cacheManager).isTransactionAware();return cacheManager;
}

3. 自行通过注解和AOP实现缓存

  • 引入AOP相关的包
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.22</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.22</version>
</dependency><!-- Jackson JSON Processor -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.8</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.8</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.8</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.28</version>
</dependency>
  • 创建@CustomCache
@Target(ElementType.METHOD)  
@Retention(RetentionPolicy.RUNTIME)
public @interface  CustomCache {  /*** key的规则,可以使用springEL表达式,可以使用方法执行的一些参数*/String key();/***  类似前缀* @return*/String value();
}
  • 修改AppConfig
@EnableAspectJAutoProxy // 开启AOP自动代理
public class AppConfig {@Bean  public RedisConnectionFactory redisConnectionFactory() {RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();redisStandaloneConfiguration.setHostName(host);redisStandaloneConfiguration.setPort(port); // 自适应集群变化RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);return redisConnectionFactory;}@Beanpublic RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate redisTemplate = new RedisTemplate();redisTemplate.setConnectionFactory(redisConnectionFactory);redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);redisTemplate.setValueSerializer(StringRedisSerializer.UTF_8);return redisTemplate;}
}
  • 创建 CustomCacheAspect
@Component  
@Aspect  
public class CustomCacheAspect {@Autowired  private RedisTemplate redisTemplate;@Pointcut("@annotation(cn.lazyfennec.cache.redis.annotation.CustomCache)")public void cachePointcut() {}@Around("cachePointcut()")public Object doCache(ProceedingJoinPoint joinPoint) {Object obj = null;try {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(), signature.getMethod().getParameterTypes());CustomCache customCache = method.getAnnotation(CustomCache.class);String cacheKey = customCache.key();String cacheValue = customCache.value(); // 创建解析器ExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(cacheKey);EvaluationContext context = new StandardEvaluationContext(); // 参数// 添加参数Object[] args = joinPoint.getArgs();DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();String[] parameterNames = discover.getParameterNames(method);for (int i = 0; i < parameterNames.length; i++) {context.setVariable(parameterNames[i], args[i].toString());}// 解析String key = cacheValue + "::" + expression.getValue(context).toString();// 1、 判定缓存中是否存在obj = redisTemplate.opsForValue().get(key);if (obj != null) return obj;// 2、不存在则继续行方法obj = joinPoint.proceed();// 3、 同步存储value到缓存。redisTemplate.opsForValue().set(key, obj);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (Throwable throwable) {throwable.printStackTrace();}return obj;}
} 
  • 新建方法 getUserNameById
@RequestMapping("/custom/name/{id}")
@ResponseBody
public String getUserNameById(@PathVariable Integer id) {return userService.getUserNameById(id);
}
  • 实际实现方法 getUserNameById,使用方式
@Override
@CustomCache(value = "custom_user", key = "#id")
public String getUserNameById(Integer id) {
return userMapper.findUserNameById(id);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/650699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

直接在GitHub上使用vscode阅读源码

方法&#xff1a; 直接在github后面输入1s即可 效果&#xff1a;

光学系统的核心--分辨率

前言 在机器视觉领域&#xff0c;可以把各个部件划分为光源&#xff0c;镜头&#xff0c;相机&#xff0c;采集卡&#xff0c;算法&#xff0c;运动平台等。各个部件都是系统的有机组合&#xff0c;均有各自的重要性。在实际应用中&#xff0c;成像镜头涉及的光学理论较多&…

[数据结构]-哈希

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习目标&…

智能工厂4G无线设备预测维护云端联动的DI、AI、DO混合信号处理单元

在现代工业智能化进程中&#xff0c;一款集成了丰富I/O接口并能与各大云平台无缝对接的智能设备显得尤为重要。比如最近推出的这款创新产品&#xff0c;它集合了8路数字输入通道&#xff0c;涵盖了干湿节点的识别功能&#xff0c;适用于多种开关量信号的读取&#xff1b;同时&a…

(八)springboot实战——springboot3下的webflux项目全局异常处理

前言 在webflux响应式编程中&#xff0c;如何处理系统运行时异常是本节的主要内容。在传统的Servlet阻塞式web项目中主要通过HandlerExceptionResolver处理器来处理&#xff0c;而在webflux响应式web项目中&#xff0c;则是通过DispatchExceptionHandler异常处理器来处理异常。…

[SWPUCTF 2018]SimplePHP1

打开环境 有查看文件跟上传文件&#xff0c;查看文件里面显示没有文件url貌似可以文件读取 上传文件里面可以上传文件。 先看一下可不可以文件读取 /etc/passwd不能读取&#xff0c;源码提示flag在f1ag.php 看看能不能读取当前的文件&#xff0c; 先把代码摘下来 file.php …

JavaScript 之 作用域变量提升闭包

一、JavaScript 代码的执行 浏览器内核是由两部分组成的&#xff0c;以 webkit 为例 WebCore&#xff1a;负责HTML解析、布局、渲染等等相关的工作JavaScriptCore&#xff1a;解析、执行 JavaScript 代码 另外一个强大的 JavaScript 引擎就是 V8 引擎 二、深入 V8 引擎原理 …

Java面向对象三大特征之多态

在之前的文章&#xff0c;我们分别介绍了类与对象、面向对象三大特征的封装、以及继承&#xff08;一&#xff09;、继承&#xff08;二&#xff09;。这一篇文章&#xff0c;我们介绍Java面向对象三大特征的最后一个——多态。 多态 多态的概述 概念&#xff1a;完成某个行为…

CVE-2024-23897 Jenkins 任意文件读取漏洞

项目介绍 Jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件项目可以进行持续集成。Jenkins是开源CI&CD软件领导者&#xff0c; 提供超过1000个插…

Java集合相关面试题

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于java面试题系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基…

C# 设置一个定时器函数

C#中&#xff0c;创建设置一个定时器&#xff0c;能够定时中断执行特定操作&#xff0c;可以用于发送心跳、正计时和倒计时等。 本文对C#的定时器简单封装一下&#xff0c;哎&#xff0c;以方便定时器的创建。 定义 using Timer System.Timers.Timer;class SetTimer {Timer …

OSPF协议基础(OSPF工作过程)

目录 OSPF基本工作原理邻居建立过程Router ID发现并建立邻居 - Hello报文OSPF邻居建立过程 链路状态信息丰富的数据链路层支持能力网络类型 - P2P网络网络类型 - 广播型网络网络类型 - NBMA网络网络类型 - P2MP网络OSPF的度量方式 报文类型及作用OSPF协议报文头部OSPF报文类型O…

k8s-调度

调度 从上面的架构图我们可以看到,调度是工作在Master,负责调度Pod&#xff0c;为POD分配Node。 调度的工作原理 #查看所有的Node kubectl get nodes 我们可以看到节点有一个Name,这就是调度的关键。 调度的步骤&#xff1a; 1 创建POD的时候每一个POD都会有一个叫NodeName的…

老板为何都对项目经理毕恭毕敬!因为这个职位一念成佛一念成魔

hello宝子们...我们是艾斯视觉擅长ui设计和前端开发10年经验&#xff01;希望我的分享能帮助到您&#xff01;如需帮助可以评论关注私信我们一起探讨&#xff01;致敬感谢感恩&#xff01; 老板为何都对项目经理毕恭毕敬&#xff01;因为这个职位一念成佛一念成魔 曾几何时&am…

Linux:命名管道及其实现原理

文章目录 命名管道指令级命名管道代码级命名管道 本篇要引入的内容是命名管道 命名管道 前面的总结中已经搞定了匿名管道&#xff0c;但是匿名管道有一个很严重的问题&#xff0c;它只允许具有血缘关系的进程进行通信&#xff0c;那如果是两个不相关的进程进行通信&#xff0…

《佛法修学概要》009-012集研讨

课程摘要 9、只有走出心中的妄想&#xff0c;才可能接觸彌陀的光明&#xff01; 佛陀在經典裡講出一個譬喻&#xff0c;說有一座動物園&#xff0c;這座動物園關了很多動物。其中有一隻袋鼠&#xff0c;就是澳洲那種很會跳的袋鼠。動物園的管理員&#xff0c;給牠圈了一個十公尺…

《合成孔径雷达成像算法与实现》Figure5.16

clc clear close all距离向参数 R_eta_c 20e3; % 景中心斜距 Tr 25e-6; % 发射脉冲时宽 Kr 0.25e12; % 距离向调频率 Fr 7.5e6; % 距离向采样率 Nrg 256; % 距离线采样点数 Bw abs(Kr*Tr); …

【vue oidc-client】invalid_requestRequest Id: 0HN0OOPFRLSF2:00000002

需求&#xff1a;完成统一登录&#xff0c;需要从三方平台跳到我们的平台。 oidc-client报错记录。这个一般是配置信息出错&#xff0c;需要和三方平台进行沟通&#xff0c;一定要把client_id&#xff0c;密钥进行对应&#xff1b; 同时关于此次出错还修改了以下代码&#xff…

主成分分析(PCA)Python

实际问题研究中&#xff0c;常常遇到多变量问题&#xff0c;变量越多&#xff0c;问题往往越复杂&#xff0c;且各个变量之间往往有联系。于是&#xff0c;我们想到能不能用较少的新变量代替原本较多的旧变量&#xff0c;且使这些较少的新变量尽可能多地保留原来变量所反映的信…

按配置数据绘制配置型地图marker的icon,自定义marker

一、需求 需要自定义配置数据的marker&#xff0c;其中图片内容要灵活可配置自动生成。此处项目用的百度地图。 效果图&#xff1a; 二、思路 用背景图canvas绘制数字的方式生成icon的图片资源。 再将icon生成对应地图marker。 三、代码 canvasImg.js <!-- * descrip…