Spring与Redis集成

news2024/12/25 1:16:14

1.引入RedisTemplate

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

    @Override
    public 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进行管理。
  @Bean
  public RedisConnectionFactory redisConnectionFactory() {
      RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
      redisStandaloneConfiguration.setHostName(host);
      redisStandaloneConfiguration.setPort(port);

      RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
      return redisConnectionFactory;
  }

  @Bean
  public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
      RedisTemplate redisTemplate = new RedisTemplate();
      redisTemplate.setConnectionFactory(redisConnectionFactory);
      //设置key值的序列化方式,默认是JDK的形式
      redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
      return redisTemplate;
  }
  • 如果使用RedisTemplate的替换的话,会简洁很多。
  @Autowired
  private RedisTemplate redisTemplate;

  @Override
  public 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的ip
    redisStandaloneConfiguration.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;
    }

    @Bean
    public 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.coloradmin.cn/o/1415943.html

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

相关文章

【YOLO系列算法俯视视角下舰船目标检测】

YOLO系列算法俯视视角下舰船目标检测 数据集和模型YOLO系列算法俯视视角下舰船目标检测YOLO系列算法俯视视角下舰船目标检测可视化结果 数据集和模型 数据和模型下载&#xff1a; YOLOv6俯视视角下舰船目标检测训练好的舰船目标检测模型舰船目标检测数据YOLOv7俯视视角下舰船…

机器学习|ROC曲线和AUC值

概念AUC&#xff08;Area Under Curve&#xff09;被定义为ROC曲线下的面积。其中&#xff0c;ROC曲线全称为受试者工作特征曲线 &#xff08;receiver operating characteristic curve&#xff09;&#xff0c; 模型会计算出所判断事物为汉堡&#x1f354;的概率&#xff0c;而…

基于DataKit迁移MySQL到openGauss

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

华为二层交换机与防火墙配置上网示例

二层交换机与防火墙对接上网配置示例 组网图形 图1 二层交换机与防火墙对接上网组网图 二层交换机简介配置注意事项组网需求配置思路操作步骤配置文件相关信息 二层交换机简介 二层交换机指的是仅能够进行二层转发&#xff0c;不能进行三层转发的交换机。也就是说仅支持二层…

[SwiftUI]系统弹窗和自定义弹窗

一、系统弹窗 在 SwiftUI 中&#xff0c;.alert 是一个修饰符&#xff0c;用于在某些条件下显示一个警告对话框。Alert 可以配置标题、消息和一系列的按钮。每个按钮可以是默认样式、取消样式&#xff0c;或者是破坏性的样式&#xff0c;它们分别对应不同的用户操作。 1.Aler…

Power ModeII 插件的下载与使用-----idea

下载 Marketplace里面搜索下载即可 使用 下载后重启软件就可以用了 下面是一些关于Power ModeII &#xff0c;我的个性化设置截图 以及相关设置解释 插件或扩展的设置面板【用于给代码编辑器或集成开发环境&#xff08;IDE&#xff09;添加视觉效果】 主要设置 ENTER POWE…

【控制算法笔记】卡尔曼滤波(二)——基于状态空间表达的KF基本计算流程以及Python实现

本文是个人学习笔记&#xff0c;包含个人理解&#xff0c;如有错误欢迎指正。 KF算法更多的情况下会用来处理复杂的非线性数据&#xff0c;尤其是当对象特征或检测的状态量不止一个时就得使用状态方程的方法&#xff0c;利用线性代数的计算方式来解决噪声的估计问题。这其中涉及…

uniapp微信小程序-请求二次封装(直接可用)

一、请求封装优点 代码重用性&#xff1a;通过封装请求&#xff0c;你可以在整个项目中重用相同的请求逻辑。这样一来&#xff0c;如果 API 发生变化或者需要进行优化&#xff0c;你只需在一个地方修改代码&#xff0c;而不是在每个使用这个请求的地方都进行修改。 可维护性&a…

Java基础数据结构之哈希表

概念 顺序结构以及平衡树 中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在 查找一个元素时&#xff0c;必须要经过关键 码的多次比较 。 顺序查找时间复杂度为 O(N) &#xff0c;平衡树中为树的高度&#xff0c;即 O( log2N ) &#xff0c;搜索的效…

应急响应-内存分析

在应急响应过程中&#xff0c;除了上述几个通用的排查项&#xff0c;有时也需要对应响应服务器进行内存的提权&#xff0c;从而分析其中的隐藏进程。 内存的获取 内存的获取方法有如下几种&#xff1a; 基于用户模式程序的内存获取&#xff1b;基于内核模式程序的内存获取&a…

SparkSql---用户自定义函数UDFUDAF

文章目录 1.UDF2.UDAF2.1 UDF函数实现原理2.2需求:计算用户平均年龄2.2.1 使用RDD实现2.2.2 使用UDAF弱类型实现2.2.3 使用UDAF强类型实现 1.UDF 用户可以通过 spark.udf 功能添加自定义函数&#xff0c;实现自定义功能。 如&#xff1a;实现需求在用户name前加上"Name:…

lv14 内核内存管理、动态分频及IO访问 12

一、内核内存管理框架 内核将物理内存等分成N块4KB&#xff0c;称之为一页&#xff0c;每页都用一个struct page来表示&#xff0c;采用伙伴关系算法维护 补充&#xff1a; Linux内存管理采用了虚拟内存机制&#xff0c;这个机制可以在内存有限的情况下提供更多可用的内存空…

docker compose实现mysql一主多从

参考了很多博客&#xff0c;死磕了几天&#xff0c;最终跑起来了&#xff0c;不容易&#xff0c;晚上喝瓶82年可乐庆祝下。 1、整体文件结构&#xff0c;这里忽略log、conf、data映射目录 2、docker-compose.yml文件内容如下&#xff1a; version: 3.3 services:mysql-master…

Android App开发-简单控件(3)——常用布局

3.3 常用布局 本节介绍常见的几种布局用法&#xff0c;包括在某个方向上顺序排列的线性布局&#xff0c;参照其他视图的位置相对排列的相对布局&#xff0c;像表格那样分行分列显示的网格布局&#xff0c;CommonLayouts以及支持通过滑动操作拉出更多内容的滚动视图。 3.3.1 线…

代码随想录算法训练DAY29|回溯5

算法训练DAY29|回溯5 491.递增子序列 力扣题目链接 给定一个整型数组, 你的任务是找到所有该数组的递增子序列&#xff0c;递增子序列的长度至少是2。 示例: 输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]] 说…

【QT】QPainter基本绘图

目录 1 QPainter绘图系统 1.1 QPainter与QPaintDevice 1.2 paintEvent事件和绘图区 1.3 QPainter绘图的主要属性 1.4 创建实例 2 QPen的主要功能 2.1 线条样式 2.2 线条端点样式 2.3 线条连接样式 3 QBrush的主要功能 4 渐变填充 5 QPainter绘制基本图形元件 5.1 基本图形元件 …

burp靶场--身份认证漏洞

burp靶场–身份认证漏洞 https://portswigger.net/web-security/authentication#what-is-authentication 1.身份认证漏洞&#xff1a; ### 身份验证漏洞 从概念上讲&#xff0c;身份验证漏洞很容易理解。然而&#xff0c;由于身份验证和安全性之间的明确关系&#xff0c;它们…

基于Java SSM框架实现学校招生信息网系统项目【项目源码+论文说明】

基于java的SSM框架实现学生招生信息网系统演示 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;学校招生信息网当然也不能排除在外。学校招生信息网是以实际运用为开发背…

【大数据】Flink 中的状态管理

Flink 中的状态管理 1.算子状态2.键值分区状态3.状态后端4.有状态算子的扩缩容4.1 带有键值分区状态的算子4.2 带有算子列表状态的算子4.3 带有算子联合列表状态的算子4.4 带有算子广播状态的算子 在前面的博客中我们指出&#xff0c;大部分的流式应用都是有状态的。很多算子都…

OpenCV 0 - VS2019配置OpenCV

1 配置好环境变量 根据自己的opencv的安装目录配置 2 新建一个空项目 3 打开 视图->工具栏->属性管理器 4 添加新项目属性表 右键项目名(我这是opencvdemo)添加新项目属性表,如果有配置好了的属性表选添加现有属性表 5 双击选中Debug|x64的刚添加的属性表 6 (重点)添…