简单的spring缓存 Cacheable学习

简单的spring缓存 Cacheable学习

1.需求

项目中有很多的方法查询的数据其实是不会经常变的,但是其整体的查询sql以及调用第三方数据获取数据花费的时间很长,现在考虑对此类型的接口进行优化,首先想到的是对其进行缓存操作,所以简单了解了一下spring的缓存注解使用,此处进行简单的整理,方便后续复习项目使用。

2.简介

@Cacheable 是 Spring 框架提供的一个缓存注解,主要用于声明式地启用方法级别的缓存功能。它允许开发人员在不改变业务逻辑的前提下,通过简单的注解配置来实现缓存机制,从而提高应用程序的性能。

  • 主要概念
    缓存(Cache): 在计算机科学中,缓存是一种用于存储经常访问的数据的技术,目的是为了加快数据的访问速度。缓存通常存储在比原始数据源(如数据库)更快的存储介质中。

    声明式缓存: 通过注解或 XML 配置来声明哪些方法应该被缓存,而不是通过编程方式显式地管理缓存逻辑。

  • 缓存的工作原理
    当一个带有 @Cacheable 注解的方法被调用时,Spring 会根据配置的缓存键(默认是基于方法参数的哈希值)去查找缓存中是否已经有该方法的执行结果。如果找到了相应的缓存条目,则直接返回缓存中的结果,不再执行方法体内的逻辑。如果没有找到,则执行方法并将其结果存储到缓存中,以便后续相同的请求可以直接从缓存中获取结果。

相对于自己编写的缓存,spring框架的自带缓存组件有以下优势:

  • 简化开发: @Cacheable 注解使得开发人员无需手动编写缓存逻辑,通过简单的注解配置即可启用缓存功能。
  • 透明性: 缓存操作对于业务逻辑来说是透明的,开发人员只需要关注业务逻辑的实现,而不需要关心缓存的具体实现细节。
  • 集中管理: 缓存策略可以通过配置文件或注解集中管理,便于维护和调整。
  • 灵活的缓存策略: 支持多种缓存管理机制,如基于时间的失效策略、基于访问次数的淘汰策略等。
  • 支持多种缓存存储: 可以很容易地集成多种缓存存储方案,如 Ehcache、Redis、Caffeine 等。
  • 减少数据库负载: 对于那些读操作远多于写操作的场景,使用 @Cacheable 可以显著减少对数据库的访问,提高应用的整体性能。
  • 自动化的缓存管理: Spring 会自动处理缓存的存储、查找和过期等操作,减少了手动管理缓存时可能引入的错误。

3. 简单的使用

3.1 简单的注解认识

我们使用spring的缓存主要使用的是 @Cacheable@CachePut@CacheEvict这三个注解,那么简单的介绍一下这三个注解

  1. @Cacheable
    作用: 用于标记一个方法,使得在调用该方法之前,Spring 会尝试从缓存中获取数据。如果缓存中有对应键的数据,则直接返回缓存中的数据,不会执行方法本身。如果缓存中没有数据,则执行方法并将结果存储到缓存中。
    用法: 通常用于那些计算成本较高、调用频繁且结果可预测的方法上。
    属性:

    • value/cacheNames: 指定缓存的名字,可以设置一个或者多个。
    • key: 定义缓存的键,默认情况下通常是基于方法参数的组合来生成键。
    • unless: 可以定义一个条件表达式,表达式为真,不缓存此方法的结果,结果result获取。eg: unless="#name.length() <=10 ",名称长度小于等于10则不缓存。
    • condition: 定义了一个条件表达式,只有当表达式为真时才缓存此方法的结果。 eg: condition="#name.length() <=10 ",名称长度小于等于10则缓存。
  2. @CachePut
    作用: 标记的方法会在每次调用后都将结果存入缓存中。与 @Cacheable 不同的是,@CachePut 总是会执行方法体内的逻辑,然后再把结果放入缓存。
    用法: 适用于那些需要先执行业务逻辑再更新缓存的情况。
    属性: 类似于 @Cacheable,可以指定 value/cacheNames、key 等属性。

  3. @CacheEvict
    作用: 用于清除缓存中的一个或多个条目。可以在方法调用前后清除缓存,这取决于 beforeInvocation 属性是否设置为 true。
    用法: 通常在修改数据之后使用,以保证缓存的一致性。
    属性:

    • value/cacheNames: 指定要清除的缓存的名字。
    • key: 定义要清除的缓存键。
    • allEntries: 如果设置为 true,则清除整个缓存。
    • beforeInvocation: 如果设置为 true,则在方法调用前清除缓存,默认为 false,即方法调用后清除。

我们编写缓存的key以及condition条件等,使用的是 spEL表达式方式,常用的表达式如下:

名称位置描述示例
methodNameroot object当前被调用的方法名称#root.methodName
methodroot object当前被调用的方法# root.method.name
targetroot object当前被调用的目标对象#root.target
targetClassroot object当前被调用的对象类#root.targetClass
argsroot object当前被调用的方法的参数列表#root.args[0]
cachesroot object当前方法调用使用的缓存列表[如 @Cacheable(value={"cache1", "cache2"}),则有两个cache]#root.caches[0].name
argument nameevaluation context方法参数的名字,可以直接使用 #参数名,也可以使用 #p0或者 #a0的形式,0代表索引#a0
resultevaluation context方法执行完毕的返回结果值(仅当方法执行后的判定有效)#result

3.2 注解的简单使用

下面简单使用注解进行信息缓存,主要测试缓存功能,则没有使用数据库查询测试,而是使用Thread.sleep进行模拟数据库查询,具体的pom以及service代码如下

  • 引入缓存使用的pom文件

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    
  • controller接口类

    package cn.git.controller;import cn.git.entity.Person;
    import cn.git.service.CacheService;
    import com.alibaba.fastjson.JSONObject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;/*** @description: 缓存测试controller* @program: bank-credit-sy* @author: lixuchun* @create: 2024-09-23*/
    @RestController
    @RequestMapping("/cache")
    public class CacheController {@Autowiredprivate CacheService cacheService;/*** 根据id获取person* @param id id*/@GetMapping("/person/{id}")public String getPersonById(@PathVariable("id") String id) {return JSONObject.toJSONString(cacheService.getPersonById(id));}/*** 根据id获取person,缓存自定义key** @param id id*/@GetMapping("/person/cus/{id}")public String getPerson(@PathVariable("id") String id) {return JSONObject.toJSONString(cacheService.getPersonByCusId(id));}/*** 更新person* @return*/@GetMapping("/update/{id}")public String updatePerson(@PathVariable("id") String id) {Person person = new Person(id, "张三", 18, "男");return JSONObject.toJSONString(cacheService.updatePerson(person));}/*** 根据id删除person* @param id id*/@GetMapping("/delete/{id}")public void deletePersonById(@PathVariable("id") String id) {cacheService.deletePersonById(id);}
    }
  • service实现代码如下

    package cn.git.service.impl;import cn.git.entity.Person;
    import cn.git.service.CacheService;
    import com.alibaba.fastjson.JSONObject;
    import org.springframework.cache.annotation.CacheEvict;
    import org.springframework.cache.annotation.CachePut;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Service;/*** @description: 缓存服务实现类* @program: bank-credit-sy* @author: lixuchun* @create: 2024-09-23*/
    @Service
    public class CacheServiceImpl implements CacheService {/*** 根据id获取person** @param id id*/@Cacheable(cacheNames = "person", key = "#id")@Overridepublic Person getPersonById(String id) {try {Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();}Person person = new Person();person.setId(id);person.setAge(18);person.setSex("男");person.setName("张三");System.out.println("获取数据成功 -> " + JSONObject.toJSONString(person));return person;}/*** 根据id获取person,缓存key自定义** @param id id*/@Cacheable(cacheNames = "person", keyGenerator = "customKeyGenerator")@Overridepublic Person getPersonByCusId(String id) {try {Thread.sleep(2000);} catch (Exception e) {e.printStackTrace();}Person person = new Person();person.setId(id);person.setAge(18);person.setSex("男");person.setName("张三");System.out.println("获取数据成功 -> " + JSONObject.toJSONString(person));return person;}/*** 更新person, 并返回person* 返回person值会被缓存,缓存的key为person的id** @param person person*/@CachePut(cacheNames = "person", key = "#person.id")@Overridepublic Person updatePerson(Person person) {person.setName("李四".concat(String.valueOf(System.currentTimeMillis())));System.out.println("更新数据成功 -> " + JSONObject.toJSONString(person));return person;}/*** 根据id删除person* 使用参数 allEntries=true 则可以删除所有缓存** @param id id*/@CacheEvict(cacheNames = "person", key = "#id")@Overridepublic void deletePersonById(String id) {System.out.println("数据删除成功 -> " + id);}
    }
  • 服务启动类添加启动缓存注解

    package cn.git;import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cache.annotation.EnableCaching;/*** @description: activiti迁移测试类* @program: bank-credit-sy* @author: lixuchun* @create: 2024-06-07*/
    @EnableCaching
    @SpringBootApplication(scanBasePackages = "cn.git")
    public class helloApplication {public static void main(String[] args) {SpringApplication.run(helloApplication.class, args);}
    }
    

4.整合redis并且实现缓存超时功能

整个spring缓存整合redis非常简单,引入整合redis必要的pom坐标文件,引入jar包后再编写redis的缓存管理器即可,具体的实现步骤如下。

  • 引入必要pom坐标

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.3.8.RELEASE</version>
    </dependency>
    <dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.8.1</version>
    </dependency>
    
  • redis配置类以及序列化处理类

    序列化类内容如下

    package cn.git.config;import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.SerializationException;
    import org.springframework.stereotype.Component;import java.nio.charset.Charset;
    import java.nio.charset.StandardCharsets;/*** @description: Redis序列化配置* @program: bank-credit-sy* @author: lixuchun* @create: 2024-09-23*/
    @Component
    public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {/*** 默认字符集*/private final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;/*** 泛型类型*/Class<T> clazz;/*** 配置全局类型支持*/static {ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}/*** 序列化构造函数** @param t*/@Overridepublic byte[] serialize(T t) throws SerializationException {if (null == t) {return new byte[0];}return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}/*** 反序列化** @param bytes*/@Overridepublic T deserialize(byte[] bytes) throws SerializationException {if (null == bytes || 0 >= bytes.length) {return null;}String str = new String(bytes, DEFAULT_CHARSET);return JSON.parseObject(str, clazz);}
    }
  • redis 缓存管理器配置类如下
    缓存超时功能主要是设置 RedisCacheConfiguration.entryTtl(Duration.ofSeconds(60)) 参数生效

    package cn.git.config;import lombok.extern.slf4j.Slf4j;
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.interceptor.KeyGenerator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheConfiguration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.serializer.RedisSerializationContext;import java.time.Duration;/*** @description: redis配置类* @program: bank-credit-sy* @author: lixuchun* @create: 2024-09-23*/
    @Slf4j
    @Configuration
    @EnableCaching
    public class RedisCacheConfig extends CachingConfigurerSupport {/*** redis序列化器*/private static final FastJson2JsonRedisSerializer REDIS_SERIALIZER = new FastJson2JsonRedisSerializer();/*** 自定义key生成器, 拼接名称class名称 + 方法名称 + 参数列表** @return*/@Bean(name = "customKeyGenerator")public KeyGenerator customKeyGenerator(){// 三个参数分别为 当前类,方法,参数列表return (object, method, params) -> {// 拼接名称class名称 + 方法名称 + 参数列表StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(object.getClass().getName());stringBuilder.append(method.getName());// 拼接参数信息for(Object param: params){stringBuilder.append(param == null ? "null" : param.toString());}return stringBuilder.toString();};}/*** 配置缓存管理器** @param connectionFactory* @return*/@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()// 设置缓存的过期时间,单位秒.entryTtl(Duration.ofSeconds(60))// 设置key的序列化方式.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(REDIS_SERIALIZER))// 设置value的序列化方式.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(REDIS_SERIALIZER))// 不缓存null值.disableCachingNullValues();// 配置缓存管理器return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build();}}
  • yml配置文件

    spring:application:name: docker-hello  # 应用程序名称,用于 Spring Cloud 的服务发现和服务注册# redis配置redis:database: 0  # Redis 数据库索引,默认为 0host: 192.168.138.129  # Redis 服务器的 IP 地址port: 6379  # Redis 服务器的端口号timeout: 20000  # Redis 连接超时时间,单位为毫秒# springboot2.x以上如此配置,由于2.x的客户端是lettucelettuce:pool:max-active: 8  # 最大活动连接数,默认为 8min-idle: 0  # 最小空闲连接数,默认为 0max-idle: 8  # 最大空闲连接数,默认为 8max-wait: 10000ms  # 获取连接的最大等待时间,默认为 10000 毫秒server:port: 8088
    

5.测试

Spring @Cacheable 默认使用的缓存管理器是ConcurrentMapCacheManager。如果没有指定其他的缓存管理器,Spring会自动使用这个默认的实现。如果我们直接使用spring @Cacheable注解,则使用的是本地ConcurrentMap进行缓存,我们不做测试了,效果不太好看,此处我们使用redis配置进行测试。

使用的redis可视化工具是RDM,我们连接到RDM,观察是没有数据的
在这里插入图片描述
下面开始进行测试

  1. 添加缓存信息
    我们调用接口 http://localhost:8088/cache/person/18,进行缓存信息,发现执行接口时间为5s,再次执行发现直接响应数据,并且RDM中已经有缓存数据
    在这里插入图片描述
    RDM中缓存信息
    在这里插入图片描述

  2. 添加自定义key缓存信息
    我们调用接口 http://localhost:8088/cache/person/cus/18 缓存自定义key缓存信息,观察RDM中自定义key样式
    在这里插入图片描述
    观察RDM中key样式,发现其为 类名称+调用类方法名称+参数 的格式生成,对应到自定义的customKeyGenerator 缓存键生成策略,并且还会在60s后自动失效。
    在这里插入图片描述

  3. 修改信息
    我们调用接口 http://localhost:8088/cache/update/18 修改name信息,发现执行速度很快,然后再次调用查询信息以及观察RDM中发现数据已经被修改。
    在这里插入图片描述
    RDM中观察缓存信息
    在这里插入图片描述
    查询接口查看缓存名称信息
    在这里插入图片描述

  4. 删除缓存信息
    我们调用 http://localhost:8088/cache/delete/18 进行缓存信息删除操作,删除后再次查询RDM发现缓存信息已经不在,调用添加缓存接口发现执行时间再次变更为5s
    在这里插入图片描述
    观察RDM信息在这里插入图片描述
    再次调用添加缓存接口,返回修改前固定名称张三
    在这里插入图片描述

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

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

相关文章

CVE-2024-46103

前言 CVE-2024-46103 SEMCMS的sql漏洞。 漏洞简介 SEMCMS v4.8中&#xff0c;SEMCMS_Images.php的search参数&#xff0c;以及SEMCMS_Products.php的search参数&#xff0c;存在sql注入漏洞。 &#xff08;这个之前就有两个sql的cve&#xff0c;这次属于是捡漏了&#x1f6…

[vulnhub] Hackademic.RTB1

第一次打靶机&#xff0c;思路看的红队笔记 https://www.vulnhub.com/entry/hackademic-rtb1,17/ 环境&#xff1a;kali Linux - 192.168.75.131&#xff0c;靶机 - 192.168.75.132 主机发现和端口扫描 扫描整个网络有哪台机子在线&#xff0c;不进行端口扫描 nmap -sP 192.16…

JavaSE高级(3)——lombok、juint单元测试、断言

一、lombok的使用 默认jvm不解析第三方注解&#xff0c;需要手动开启 链式调用 二、juint单元测试 下载juint包 public class TestDemo {// 在每一个单元测试方法执行之前执行Beforepublic void before() {// 例如可以在before部分创建IO流System.out.println("befor…

力扣周赛 —— 416

前言 只做出了第一道&#xff0c;第二第三道都超时。 痛&#xff0c;太痛了。 题目 Q1.举报垃圾信息 给你一个字符串数组 message 和一个字符串数组 bannedWords。 如果数组中 至少 存在两个单词与 bannedWords 中的任一单词 完全相同&#xff0c;则该数组被视为 垃圾信息。…

HTML讲解(三)通用部分

目录 1.空格标记 2.特殊文字的标记 3.注释语句 4.对文字字体的设置 5.修改文字形态 6.换行标记 7.居中标记 8.水平线标记 9.设置滚动弹幕 1.空格标记 在HTML中&#xff0c;我们想打印空格并不能直接敲一个空格键&#xff0c;因为如果是敲空格键&#xff0c;那无论你敲…

【已解决】ElementPlus 的 el-menu 组件如何用 js 控制展开某个子菜单,并在其他组件中控制使用呢?

文章目录 需求几次探索官网寻找线索&#xff08;解决办法&#xff09; 需求 我如何用代码来实现 ElementPlus 的菜单的展开和收缩呢&#xff1f; 几次探索 尝试通过找到节点之后&#xff0c;使用 click 事件&#xff0c;失败了 // 伪代码如下 const handleFindNodeAndClick …

vue Echart使用

一、在vue中使用Echarts 1.安装Echarts npm install echarts --save2.准备一个呈现图表的盒子 给盒子起名字是建议使用id选择器 这个盒子通常来说就是我们熟悉的 div &#xff0c;这个 div 决定了图表显示在哪里&#xff0c;盒子一定要指定宽和高 <div id"main&quo…

Scott Brinker:营销运营这一角色很棒可能会变得更棒;以下是关于相关职位的最新数据

营销运营职位晋升频繁 如果你在市场营销部门工作&#xff0c;生活可能相当不错。74%的营销人员表示&#xff0c;他们对自己的角色有些满意或非常满意。在过去的一年里&#xff0c;超过一半的人得到了晋升或找到了新工作。平均而言&#xff0c;他们的薪水比组织中其他类型的营销…

二、八、十、十六进制的相互转换(期末考试必备)

本文中写的计算方法和计算流程不一定就是正确规范的。。。 参考&#xff0c;仅供参考&#xff0c;如果有问题欢迎指出 目录 一、二进制 1.1 【二】进制转换【十】进制 1.2 【二】进制转换【八】进制 1.3 【二】进制转换【十六】进制 二、八进制 2.1 【八进制】转【二进…

Vue学习记录之八(局部组件,全局组件,递归组件,动态组件)

一、局部组件 在src\components\Card.vue 建立一个文件&#xff0c;代码如下&#xff1a; <template><div class"card"><header><div>标题</div><div>副标题</div></header><section>内容</section>&…

【HTML5】html5开篇基础(1)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

【标准库的典型内容】std::declval

一、 d e c l v a l declval declval的基本概念和常规范例 s t d : : d e c l v a l std::declval std::declval 是 C 11 C11 C11标准中出现的一个函数模板。这个函数模板设计的比较奇怪&#xff08;没有实现&#xff0c;只有声明&#xff09;&#xff0c;因此无法被调用&…

Android15之编译Cuttlefish模拟器(二百三十一)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

OpenCV特征检测(5)检测图像中的角点函数cornerMinEigenVal()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算用于角点检测的梯度矩阵的最小特征值。 该函数类似于 cornerEigenValsAndVecs&#xff0c;但它计算并存储协方差矩阵导数的最小特征值&…

MovieLife 电影生活

MovieLife 电影生活 今天看到一个很有意思的项目&#xff1a;https://www.lampysecurity.com/post/the-infinite-audio-book “我有一个看似愚蠢的想法。通常&#xff0c;这类想法只是一闪而过&#xff0c;很少会付诸实践。但这次有所不同。假如你的生活是一部电影&#xff0c…

vi | vim基本使用

vim三模式&#xff1a;① 输入模式 ②命令模式 ③末行模式&#xff08;编辑模式&#xff09; vim四模式&#xff1a;① 输入模式 ②命令模式 ③末行模式&#xff08;编辑模式&#xff09; ④V模式 一、命令模式进入输入模式方法&#xff1a; 二、命令模式基…

影刀RPA实战:java结合影刀同步采购订单数据

1.实战目标 本次实战我们用java语言结合影刀&#xff0c;实现从自用ERP系统同步订单到旺店通中&#xff0c;在工作中&#xff0c;有时候我们的运营数据不是直接在旺店通ERP中操作&#xff0c;比如我们有自己的ERP&#xff0c;完成一些特定的内部工作后&#xff0c;再把数据同步…

Rustrover2024.2 正式发布:个人非商用免费,泰裤辣

如果这个世界本身 已经足够荒唐 那究竟什么才能算是疯狂 爱情就是这样 一旦错过了 就会有另一个人代替 我们知道 jetbrains 在今年的早些时候正式为 rust 语言发布了专用的 IDE &#xff0c;也就是 rustrover。如今 rustrover 也正式跻身为 jetbrains IDE 系列的一员猛将。…

Python | Leetcode Python题解之第424题替换后的最长重复字符

题目&#xff1a; 题解&#xff1a; class Solution:def characterReplacement(self, s: str, k: int) -> int:num [0] * 26n len(s)maxn left right 0while right < n:num[ord(s[right]) - ord("A")] 1maxn max(maxn, num[ord(s[right]) - ord("…

Linux学习笔记13---GPIO 中断实验

中断系统是一个处理器重要的组成部分&#xff0c;中断系统极大的提高了 CPU 的执行效率&#xff0c;本章会将 I.MX6U 的一个 IO 作为输入中断&#xff0c;借此来讲解如何对 I.MX6U 的中断系统进行编程。 GIC 控制器简介 1、GIC 控制器总览 I.MX6U(Cortex-A)的中断控制器…