当前位置: 首页 > news >正文

@Cacheable缓存相关使用总结

本篇文章主要讲解Spring当中@Cacheable缓存相关使用

在实际项目开发中,有些数据是变更频率比较低,但是查询频率比较高的,此时为了提升系统性能,可以使用缓存的机制实现,避免每次从数据库获取

第一步:使用@EnableCaching注解开启缓存

开启缓存功能,配置类中需要加上这个注解,有了这个注解之后,spring才知道你需要使用缓存的功能,其他和缓存相关的注解才会有效,Spring中主要是通过aop实现的,通过aop来拦截需要使用缓存的方法,实现缓存的功能

第二步:在方法或类上添加@Cacheable注解,表明某一个方法或者某一个类里的所有方法开启缓存功能;
@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。

对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的(因为是Aop实现的,Aop是核心是代理,内部调用无法被代理,也就不会生效)。@Cacheable可以指定三个属性,value、key和condition。

测试相关的类如下:ArticleService主要是提供模拟缓存的接口

package com.ym.example.demo.cachable;import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Component;import java.util.*;@Component
public class ArticleService {private Map<Long, String> articleMap = new HashMap<>();@Cacheable(cacheNames = {"cacheTest"})public List<String> list(){System.out.println("获取文章列表");return Arrays.asList("Spring", "MySQL", "java高并发", "Maven");}@Cacheable(value = {"cacheTest"})public List<String> listValue(){System.out.println("获取文章列表");return Arrays.asList("Spring", "MySQL", "java高并发", "Maven");}/*** @Author yangming* @Description* @Cacheable可以标记在方法上,也可以标记在一个类上,当标记在一个方法上是,表示该方法时支持缓存的,当标记到一个类上时,则表示该类所有的方法都是支持缓存的* 对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。* Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略* 这里需要注意,因为Spring缓存是通过aop实现的,aop又是依赖的代理模式,所以当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的* value和cacheNames一样,都是指定缓存的名称,这个cache名称可以是一个,也可以是多个,需要指定多个cache时其是一个数组* 可以将Cache理解为一个HashMap,系统中可以有很多歌Cache,每个Cache都有一个名字,你需要将方法的返回值放在哪个缓存中,需要通过缓存的名称来指定* key属性用来指定Spring缓存方法的返回结果时对应的key,因为Cache可以理解为一个HashMap,缓存以key-value的形式存储在HashMap中,value就是需要缓存的值(即方法返回值)* key属性支持spel表达式,当我们没有指定该属性时,Spring将使用默认策略生成key(org.springframework.cache.interceptor.SimpleKeyGenerator),默认会以方法参数创建key* 自定义策略是指我们可以通过SpEL表达式来指定我们的key,这里的SpEL表达式可以使用方法参数及他们对应的属性,使用方法参数时我们可以直接使用"#参数名"或者"#p参数index"* Spring还未我们提供了一个root对象可以用来生成key,通过该root对象我们可以获取到以下信息* methodName  当前方法名                #root.methodName* method      当前方法                  #root.method.name* target      当前被调用的对象            #root.target* targetClass 当前被调用的对象的class     #root.targetClass* args        当前方法参数组成的数组       #root.args[0]* caches      当前被调用的方法使用的cache  #root.caches[0].name** @Date 2023/8/12 10:36* @param page* @param pageSize**/@Cacheable(value = {"cacheTest"}, key = "#root.target.class.name+'-'+#page+'-'+#pageSize")public String getPage(int page, int pageSize){String msg = String.format("page-%s-pageSize-%s", page, pageSize);System.out.println("从db中获取数据: " + msg);return msg;}/*** @Author yangming* @Description 没有指定key。默认为方法参数创建key,该方法的key为SimpleKey [1,10]* @Date 2023/8/12 10:55* @param page* @param pageSize**/@Cacheable(value = {"cacheTest"})public String getPageKey(int page, int pageSize){String msg = String.format("page-%s-pageSize-%s", page, pageSize);System.out.println("从db中获取数据: " + msg);return msg;}/*** @Author yangming* @Description 没有指定key。默认为方法参数创建key,该方法的key为SimpleKey []* @Date 2023/8/12 10:55**/@Cacheable(value = {"cacheTest"})public String getPageKey(){String msg = "测试key";System.out.println("从db中获取数据: " + msg);return msg;}/*** @Author yangming* @Description 有时候希望方法调用走缓存,有时候不希望走缓存,condition为true表示先尝试从缓存中取,如果缓存中没有,则执行方法,并将方法返回结果放到缓存中,*             condition为false表示不走缓存,直接执行方法,并且返回的结果也不会放到缓存中* @Date 2023/8/11 19:39* @param id* @param cache**/@Cacheable(cacheNames = "cacheTest", key="'getById'+#id", condition = "#cache")public String getById(Long id, boolean cache){System.out.println("getById获取数据!");return "Spring缓存: " + UUID.randomUUID().toString();}/*** @Author yangming* @Description 当condition为空或者为true的情况下,unless才有效,condition为false的时候,unless无效,*             unless为true,表示方法防结果不放到缓存中,unless为false,表示方法返回结果要放到缓存中* condition和unless对比* 缓存的使用过程中有两个点:* 1、查询缓存中是否有数据;* 2、如果缓存中没有数据,则去执行目标方法,然后将方法结果放到缓存中* Spring中通过condition和unless对这2点进行干预* condition作用在上面2个点的过程中,当为true的时候,会尝试从缓存中获取数据,如果没有,会执行方法,然后将方法返回值丢到缓存中;*                               当为false的时候,则直接调用目标方法,并且结果不会放到缓存中* unless在condition为true的时候才有效,用来判断上面的第2点,看要不要将执行结果放到缓存中,*                               如果为true,表示执行的结果不放到缓存中,*                               如果为false,表示执行的结果要放到缓存中,在unless中可以使用spel表达式通过#result来获取方法返回值* @Date 2023/8/11 19:50* @param id**/@Cacheable(cacheNames = "cacheTest", key = "'findById'+#id", unless = "#result==null")public String findById(Long id){this.articleMap.put(1L, "Spring系列");System.out.println("-----获取文章: " + id + "-------");return this.articleMap.get(id);}/*** @Author yangming* @Description @CachePut也可以标注在类或者方法上,被标注的方法每次都会被调用,然后方法执行完毕之后,会将方法结果放到缓存中;当标注在类上,相当于在类的所有方法上都标注了@CachePut* @CachePut有3种情况,结果不会放到缓存* 1、当方法向外抛出异常的时候* 2、当condition的计算结果为false的时候* 3、unless的计算结果为true的时候* value,cacheNames,key,condition,unless的用法和@Cacheable中类似* @Date 2023/8/12 11:05* @param id* @param content**/@CachePut(cacheNames = "cacheTest", key = "'findById'+#id")public String add(Long id, String content){System.out.println("新增文章: " + id);this.articleMap.put(id, content);return content;}/*** @Author yangming* @Description @CacheEvict是用来清除缓存的,可以标注在类或者方法上,被标注在方法上,则目标方法被调用的时候,会清除指定的缓存;当标注在类上,相当于在类的所有方法上标注了@CacheEvict* value,cacheNames,key,condition的用法和@Cacheable中类似,@CacheEvict多了allEntries和beforeInvocation属性* allEntries:表示是否清理cacheNames指定的缓存中的所有缓存信息,默认为false*             可以将cache理解为一个HashMap,当allEntries为true的时候,相当于HashMap.clear(),*             当allEntries为false的时候,只会干掉key对应的数据,相当于HashMap.remove(key)* beforeInvocation:表示何时执行清除操作(方法执行前 or 方法执行成功之后)*              true:表示@CacheEvict 标注的方法执行之前,执行清除操作*              false:表示@CacheEvict 标注的方法执行成功之后,执行清除操作,当方法弹出异常的时候,不会执行清除操作* @Date 2023/8/12 11:25* @param id**/@CacheEvict(cacheNames = "cacheTest", key = "'findById'+#id")public void delete(Long id){System.out.println("根据id删除文章: " + id);this.articleMap.remove(id);}@Caching(cacheable = {@Cacheable(value = "cacheTest", key="#root.methodName")},put={@CachePut(value = "cacheTest", key = "#root.methodName")})public void testCaching(){}
}

CacheConfig提供缓存相关的配置,这个CacheMangager有多种实现,本例是使用的ConcurrentMapCacheManager实现,也可以是RedisCacheManager的实现

package com.ym.example.demo.cachable;import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;/*** @author yangming* @date 2023/8/11 19:24* @desc @EnableCaching表示开启缓存,有了这个注解之后,Spring才知道你需要使用缓存的功能,其他和缓存相关的注解才会生效*       Spring中主要是通过aop实现的,通过aop来拦截需要使用缓存的方法,实现缓存的功能* @package com.ym.example.demo.cachable*/
@EnableCaching
@ComponentScan
@Configuration
public class CacheConfig {/*** @Author yangming* @Description 开启缓存之后,还需要在配置类中定义一个bean,作为缓存管理器,类型为CacheManager,*             CacheManager是一个接口,有好几个实现,比如使用redis,ConcurrentMap为存储缓存信息,*             本例使用的是ConcurrentMapCacheManager,内部使用ConcurrentHashMap将缓存信息直接存储在本地jvm内存中*             不过线上环境一般是集群的方式,可以通过redis实现* @Date 2023/8/12 10:45**/@Beanpublic CacheManager cacheManager(){ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager("cacheTest");return cacheManager;}
}

CacheTest是测试相关的方法

package com.ym.example.demo.cachable;import org.junit.Test;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;/*** @author yangming* @date 2023/8/11 19:26* @package com.ym.example.demo.cachable*/
public class CacheTest {@Testpublic void test(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);System.out.println(articleService.list());System.out.println(articleService.list());}执行结果:获取文章列表[Spring, MySQL, java高并发, Maven][Spring, MySQL, java高并发, Maven]@Testpublic void test1(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//page=1,pageSize=10调用2次System.out.println(articleService.getPage(2, 10));System.out.println(articleService.getPage(2, 10));//page=2,pageSize=10调用2次System.out.println(articleService.getPage(3, 10));System.out.println(articleService.getPage(3, 10));{System.out.println("下面打印出cacheTest缓存中的key列表");ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);ConcurrentMapCache cacheTest = (ConcurrentMapCache) cacheManager.getCache("cacheTest");cacheTest.getNativeCache().keySet().stream().forEach(System.out::println);}}执行结果:从db中获取数据: page-2-pageSize-10page-2-pageSize-10page-2-pageSize-10从db中获取数据: page-3-pageSize-10page-3-pageSize-10page-3-pageSize-10下面打印出cacheTest缓存中的key列表com.ym.example.demo.cachable.ArticleService-3-10com.ym.example.demo.cachable.ArticleService-2-10@Testpublic void test2(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//第一次,缓存中没有,执行方法,将结果放到缓存System.out.println(articleService.getById(1L, true));//第二次,缓存中有,直接从缓存中获取System.out.println(articleService.getById(1L, true));//第三次,condition为false,表示不从缓存取,直接执行方法,同时方法执行结果也不放到缓存System.out.println(articleService.getById(1L, false));//第四次,condition为true,缓存有,直接从缓存中取System.out.println(articleService.getById(1L, true));}执行结果:getById获取数据!Spring缓存: 1df6227d-53ae-46a6-9a70-a85e32e39f08Spring缓存: 1df6227d-53ae-46a6-9a70-a85e32e39f08getById获取数据!Spring缓存: 7ff6c668-87f1-4432-8844-61bf66b6e3efSpring缓存: 1df6227d-53ae-46a6-9a70-a85e32e39f08@Testpublic void test3(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//第一次,没有缓存,执行方法,unless为false,表示执行结果要放到缓存中System.out.println(articleService.findById(1L));//第二次,第一次之后,缓存有数据,直接从缓存中取数据System.out.println(articleService.findById(1L));//第三次,缓存中没有,执行方法,result==null,unless为true,表示执行结果不放到缓存中System.out.println(articleService.findById(2L));//第四次,为了验证第三次的结论System.out.println(articleService.findById(2L));{System.out.println("下面打印出cacheTest缓存中的key列表");ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);ConcurrentMapCache cacheTest = (ConcurrentMapCache) cacheManager.getCache("cacheTest");cacheTest.getNativeCache().keySet().stream().forEach(System.out::println);}}执行结果:-----获取文章: 1-------Spring系列Spring系列-----获取文章: 2-------null-----获取文章: 2-------null下面打印出cacheTest缓存中的key列表findById1@Testpublic void test4(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);articleService.getPageKey(1,10);articleService.getPageKey();{System.out.println("下面打印出cacheTest缓存中的key列表");ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);ConcurrentMapCache cacheTest = (ConcurrentMapCache) cacheManager.getCache("cacheTest");cacheTest.getNativeCache().keySet().stream().forEach(System.out::println);}}执行结果:从db中获取数据: page-1-pageSize-10从db中获取数据: 测试key下面打印出cacheTest缓存中的key列表SimpleKey []SimpleKey [1,10]@Testpublic void test5(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//增加2个文章,由于add方法上有@CachePut注解,所以新增之后会自动丢到缓存中articleService.add(1L, "java高并发系列");articleService.add(2L, "MySQL高手系列");//然后调用findById获取,看看是否会走缓存System.out.println("调用findById方法,会尝试从缓存中获取");System.out.println(articleService.findById(1L));System.out.println(articleService.findById(2L));{System.out.println("下面打印出cacheTest缓存中的key列表");ConcurrentMapCacheManager cacheManager = context.getBean(ConcurrentMapCacheManager.class);ConcurrentMapCache cacheTest = (ConcurrentMapCache) cacheManager.getCache("cacheTest");cacheTest.getNativeCache().keySet().stream().forEach(System.out::println);}}执行结果:新增文章: 1新增文章: 2调用findById方法,会尝试从缓存中获取java高并发系列MySQL高手系列下面打印出cacheTest缓存中的key列表findById2findById1@Testpublic void test6(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(CacheConfig.class);context.refresh();;ArticleService articleService = context.getBean(ArticleService.class);//第一次调用findById,缓存中没有,则调用方法,将结果丢到缓存中System.out.println(articleService.findById(1L));//第二次调用findById,缓存存在,直接从缓存中取System.out.println(articleService.findById(1L));//执行删除操作,delete方法上加了@CacheEvict注解,会清除缓存articleService.delete(1L);//再次调用findById方法,缓存中没有了,则会调用目标方法System.out.println(articleService.findById(1L));}执行结果:-----获取文章: 1-------Spring系列Spring系列根据id删除文章: 1-----获取文章: 1-------Spring系列
}

@Caching:缓存注解组
当我们在类上或者同一个方法上同时使用@Cacheable、@CachePut和@CacheEvic这几个注解中的多个的时候,此时可以使用@Caching这个注解来实现
 

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {
Cacheable[] cacheable() default {};
CachePut[] put() default {};
CacheEvict[] evict() default {};
}

@CacheConfig:提取公共配置
这个注解标注在类上,可以将其他几个缓存注解(@Cacheable、@CachePut和@CacheEvic)的公共参数给提取出来放在@CacheConfig中。比如当一个类中有很多方法都需要使用(@Cacheable、@CachePut和@CacheEvic)这些缓存注解的时候,大家可以看一下这3个注解的源码,他们有很多公共的属性,比如:cacheNames、keyGenerator、cacheManager、cacheResolver,若这些属性值都是一样的,可以将其提取出来,放在@CacheConfig中,不过这些注解(@Cacheable、@CachePut和@CacheEvic)中也可以指定属性的值对@CacheConfig中的属性值进行覆盖。

@CacheConfig(cacheNames = "cache1")
public class ArticleService {@Cacheable(key = "'findById'+#id")public String findById(Long id) {this.articleMap.put(1L, "spring系列");System.out.println("----获取文章:" + id);return articleMap.get(id);}
}

spring中的缓存主要是利用spring中aop实现的,通过Aop对需要使用缓存的bean创建代理对象,通过代理对象拦截目标方法的执行,实现缓存功能。重点在于 @EnableCaching 这个注解,可以从 @Import 这个注解看起
 

@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {}

最终会给需要使用缓存的bean创建代理对象,并且会在代理中添加一个拦截器
org.springframework.cache.interceptor.CacheInterceptor ,这个类中的 invoke 方法是关键,
会拦截所有缓存相关的目标方法的执行,有兴趣可以去细看一下。
 

相关文章:

@Cacheable缓存相关使用总结

本篇文章主要讲解Spring当中Cacheable缓存相关使用 在实际项目开发中&#xff0c;有些数据是变更频率比较低&#xff0c;但是查询频率比较高的&#xff0c;此时为了提升系统性能&#xff0c;可以使用缓存的机制实现&#xff0c;避免每次从数据库获取 第一步&#xff1a;使用E…...

c++ static

static 成员 声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff1b;用 static修饰的成员函数&#xff0c;称之为静态成员函数。静态成员变量一定要在类外进行初始化。 看看下面代码体会一下: //其他类 class …...

【数据结构】——栈、队列的相关习题

目录 题型一&#xff08;栈与队列的基本概念&#xff09;题型二&#xff08;栈与队列的综合&#xff09;题型三&#xff08;循环队列的判空与判满&#xff09;题型四&#xff08;循环链表表示队列&#xff09;题型五&#xff08;循环队列的存储&#xff09;题型六&#xff08;循…...

C++初阶之一篇文章教会你list(模拟实现)

list&#xff08;模拟实现&#xff09; list模拟实现list_node节点结构定义std::__reverse_iterator逆向迭代器实现list迭代器 __list_iterator定义list类成员定义list成员函数定义1.begin()、end()、rbegin()和rend()2.empty_init()3.构造函数定义4.swap5.析构函数定义6.clear…...

设备工单管理系统如何实现工单流程自动化?

设备工单管理系统属于工单系统的一种&#xff0c;基于其丰富的功能&#xff0c;它可以同时处理不同的多组流程&#xff0c;旨在有效处理发起人提交的事情&#xff0c;指派相应人员完成服务请求和记录全流程。该系统主要面向后勤管理、设备维护、物业管理、酒店民宿等服务行业设…...

ubuntu20.04.6anzhuang mtt s80

需要打开主板的Resize BAR和Above 4G功能&#xff0c;否则GPU显存不能被正确识别; 2. 在某些不支持PCIe Gen5的主板上&#xff0c;需要把PCIe速率由auto设置为PCIe Gen4速率&#xff1b; sudo apt install lightdm unity-greetersheding lightdm : lightdm sudo apt install /…...

【LeetCode-中等】剑指 Offer 36. 二叉搜索树与双向链表

题目链接 剑指 Offer 36. 二叉搜索树与双向链表 标签 后序遍历、二叉搜索树 步骤 二叉搜索树中的任一节点的直接前驱为其左子树的最右侧节点&#xff0c;直接后继为其右子树的最左侧节点。因此&#xff0c;可以通过这个关系来操作原来的二叉树。为了不影响深度较大的节点的…...

Linux —— 文件系统

目录 一&#xff0c;背景 二&#xff0c;文件系统 一&#xff0c;磁盘简介 磁盘分为SSD、机械磁盘&#xff1b;机械磁盘&#xff0c;即磁盘高速转动&#xff0c;磁头移动到读写扇区所在磁道&#xff0c;让磁头在目标扇区上划过&#xff0c;即可完成对扇区的读写操作&#xff…...

自然策略优化的解释 Natural Policy Optimization

Natural Policy Optimization&#xff08;自然策略优化&#xff09;是一种用于优化策略梯度算法的方法。它是基于概率策略的强化学习算法&#xff0c;旨在通过迭代地更新策略参数来最大化累积回报。 传统的策略梯度算法通常使用梯度上升法来更新策略参数&#xff0c;但这种方法…...

docker基本使用方法

docker使用 1. Docker 介绍 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。Docker 使您能够将应用程序与基础架构分开&#xff0c;从而可以快速交付软件。通过利用 …...

机器学习(十八):Bagging和随机森林

全文共10000余字&#xff0c;预计阅读时间约30~40分钟 | 满满干货(附数据及代码)&#xff0c;建议收藏&#xff01; 本文目标&#xff1a;理解什么是集成学习&#xff0c;明确Bagging算法的过程&#xff0c;熟悉随机森林算法的原理及其在Sklearn中的各参数定义和使用方法 代码…...

使用蓝牙外设却不小心把台式机电脑蓝牙关了

起因 今天犯了一个贼SB的错误&#xff0c;起因是蓝牙键盘突然就不能输入了&#xff08;虽然是连接状态&#xff0c;但是按什么键都没有反应&#xff09; 原来我的解决方法就是重启一下电脑&#xff0c;但是那会电脑开了贼多的软件。我就想重启也太麻烦了&#xff0c;既然重启…...

美国Linux服务器安装Grafana和配置zabbix数据源的教程

美国Linux服务器的Grafana工具是跨平台、开源、时序和可视化面板Dashboard监控平台工具&#xff0c;是在日常管理中帮忙提高效率的实用工具&#xff0c;可以通过将采集的美国Linux服务器系统数据查询后&#xff0c;进行可视化的展示及通知&#xff0c;本文小编就来介绍下美国Li…...

[ROS安装问题] rosdep update 失败报错

【关于ROS安装】 由于日益复杂的国际形势&#xff0c;按照wiki官网的ROS安装流程变得相当困难&#xff0c;这里我推荐使用鱼香ROS大佬写的脚本一键傻瓜式安装&#xff1a; wget http://fishros.com/install -O fishros && . fishros 【关于rosdep失败】 这已经是一…...

Vue2到3 Day5 全套学习内容,众多案例上手(内付源码)

简介&#xff1a; Vue2到3 Day1-3 全套学习内容&#xff0c;众多案例上手&#xff08;内付源码&#xff09;_星辰大海1412的博客-CSDN博客本文是一篇入门级的Vue.js介绍文章&#xff0c;旨在帮助读者了解Vue.js框架的基本概念和核心功能。Vue.js是一款流行的JavaScript前端框架…...

STM32 CubeMX (uart_IAP串口)简单示例

STM32 CubeMX STM32 CubeMX &#xff08;串口IAP&#xff09; STM32 CubeMXIAP有什么用&#xff1f;整体思路 一、STM32 CubeMX 设置时钟树UART使能UART初始化设置 二、代码部分文件移植![在这里插入图片描述](https://img-blog.csdnimg.cn/0c4841d8328b4169a8833f15fe3d670c.p…...

Kafka:安装和配置

producer&#xff1a;发布消息的对象&#xff0c;称为消息产生者 &#xff08;Kafka topic producer&#xff09; topic&#xff1a;Kafka将消息分门别类&#xff0c;每一个消息称为一个主题&#xff08;topic&#xff09; consumer&#xff1a;订阅消息并处理发布消息的对象…...

786. 第k个数

文章目录 QuestionIdeasCode Question 给定一个长度为 n 的整数数列&#xff0c;以及一个整数 k &#xff0c;请用快速选择算法求出数列从小到大排序后的第 k 个数。 输入格式 第一行包含两个整数 n 和 k 。 第二行包含 n 个整数&#xff08;所有整数均在 1∼109 范围内&…...

用友-NC-Cloud远程代码执行漏洞[2023-HW]

用友-NC-Cloud远程代码执行漏洞[2023-HW] 一、漏洞介绍二、资产搜索三、漏洞复现PoC小龙POC检测脚本: 四、修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#…...

Transformer(二)(VIT,TNT)(基于视觉CV)

目录 1.视觉中的Attention 2.VIT框架&#xff08;图像分类&#xff0c;不需要decoder&#xff09; 2.1整体框架 2.2.CNN和Transformer遇到的问题 2.3.1CNN 2.3.2Transformer 2.3.3二者对比 2.4.公式理解 3TNT 参考文献 1.视觉中的Attention 对于人类而言看到一幅图可以立…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...