@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 方法是关键,
会拦截所有缓存相关的目标方法的执行,有兴趣可以去细看一下。
 

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

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

相关文章

没学C++,如何从C语言丝滑过度到python【python基础万字详解】

大家好&#xff0c;我是纪宁。 文章将从C语言出发&#xff0c;深入介绍python的基础知识&#xff0c;也包括很多python的新增知识点详解。 文章目录 1.python的输入输出&#xff0c;重新认识 hello world&#xff0c;重回那个激情燃烧的岁月1.1 输出函数print的规则1.2 输入函…

【Java从0到1学习】09 正则表达式

1. 正则表达式概述 在编写处理字符串的程序或网页时&#xff0c;经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说&#xff0c;正则表达式就是记录文本规则的代码。 正则表达式&#xff0c;又称正规表示法、常规表示法&#xff…

机器学习笔记:李宏毅diffusion model

1 概念原理 首先sample 一个都是噪声的vector然后经过denoise network 过滤一些杂质接着继续不断denoise&#xff0c;直到最后出来一张清晰图片 【类似于做雕塑&#xff0c;一开始只是一块石头&#xff08;噪声很杂的雕塑&#xff09;&#xff0c;慢慢雕刻出想要的花纹】 同一个…

飞天使-jenkins进行远程linux机器修改某个文件的思路

文章目录 jenkins配置的方式jenkins中执行shell的思路 jenkins配置的方式 jenkins中执行shell的思路 下面的脚本别照抄&#xff0c;只是一个思路 ipall"$ips"# 将文本参数按行输出为变量 while IFS read -r line; doecho "$line" if [[ ! -z $line ]] &…

Android CameraX适配Android13的踩坑之路

AndroidCameraX适配Android13的踩坑之路 前言&#xff1a; 最近把AGP插件升级到8.1.0&#xff0c;新建项目的时候目标版本和编译版本都是33&#xff0c;发现之前的demo使用Camerax拍照和录像都失败了&#xff0c;于是查看了一下官网和各种资料&#xff0c;找到了Android13的适…

PHP实践:分布式场景下的Session共享解决方案实现

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责…

LVS的负载均衡集群

基于四层协议进行 什么是集群 含义: 1、cluster 集群、群集 2、多台主机构成&#xff0c;但对外之表现为一个整体只提供一个访问入口&#xff08;域名和地址&#xff09;相当于一台大型计算机 目前互联网应用中&#xff0c;随着站点对硬件性能、响应速度、服务稳定性、数据…

使用 `tailwindcss-patch@2` 来提取你的类名吧

使用 tailwindcss-patch2 来提取你的类名吧 使用 tailwindcss-patch2 来提取你的类名吧 安装使用方式 命令行 Cli 开始提取吧 Nodejs API 的方式来使用 配置 初始化 What’s next? tailwindcss-patch 是一个 tailwindcss 生态的扩展项目。也是 tailwindcss-mangle 项目重要…

《起风了》C++源代码

使用方法 Visual Studio、Dev-C、Visual Studio Code等C/C创建一个 .cpp 文件&#xff0c;直接粘贴赋值即可。 #include <iostream> #include <Windows.h> #pragma comment(lib,"winmm.lib") using namespace std; enum Scale {Rest 0, C8 108, B7 …

【Linux】以太网协议——数据链路层

链路层解决的问题 IP拥有将数据跨网络从一台主机送到另一台主机的能力&#xff0c;但IP并不能保证每次都能够将数据可靠的送到对端主机&#xff0c;因此IP需要上层TCP为其提供可靠性保证&#xff0c;比如数据丢包后TCP可以让IP重新发送数据&#xff0c;最终在TCP提供的可靠性机…

SpringBoot后端服务开启Https协议提供访问(使用阿里云资源)

目录 概述 申请/下载证书 部署证书 本地测试访问 服务器部署访问 最后/扩展 总结 概述 本篇博客说明如何将SpringBoot项目开启Https协议提供访问。 博文以步骤【申请/下载证书】&#xff0c;【部署证书】&#xff0c;【本地测试访问】&#xff0c;【服务器部署访问】 &a…

【Java】BF算法(串模式匹配算法)

☀️ 什么是BF算法 BF算法&#xff0c;即暴力算法&#xff0c;是普通的模式匹配算法&#xff0c;BF算法的思想就是将目标串S的第一个与模式串T的第一个字符串进行匹配&#xff0c;若相等&#xff0c;则继续比较S的第二个字符和T的第二个字符&#xff1b;若不相等&#xff0c;则…

迭代器模式-遍历聚合对象中的元素

在开发中&#xff0c;我们经常使用到Iterator这个接口&#xff0c;我们很疑惑于这个接口的作用&#xff0c;认为集合已经实现了数据访问的方法&#xff0c;增加Iterator的意义在哪。本文我们将学习迭代器模式&#xff0c;用以探讨Iterator的作用。 1.1 迭代器模式概述 提供一…

LeetCode 160.相交链表

文章目录 &#x1f4a1;题目分析&#x1f4a1;解题思路&#x1f6a9;步骤一&#xff1a;找尾节点&#x1f6a9;步骤二&#xff1a;判断尾节点是否相等&#x1f6a9;步骤三&#xff1a;找交点&#x1f344;思路1&#x1f344;思路2 &#x1f514;接口源码 题目链接&#x1f449;…

LAXCUS分布式操作系统:技术创新引领高性能计算与人工智能新时代

随着科技的飞速发展&#xff0c;高性能计算、并行计算、分布式计算、大数据、人工智能等技术在各个领域得到了广泛应用。在这个过程中&#xff0c;LAXCUS分布式操作系统以其卓越的技术创新和强大的性能表现&#xff0c;成为了业界的佼佼者。本文将围绕LAXCUS分布式操作系统的技…

Jmeter 参数化的几种方法

目录 配置元件-用户自定义变量 前置处理器-用户参数 配置元件-CSV Data Set Config Tools-函数助手 配置元件-用户自定义变量 可在测试计划、线程组、HTTP请求下创建用户定义的变量 全局变量&#xff0c;可以跨线程组调用 jmeter执行的时候&#xff0c;只获取一次&#xff0…

LeetCode-101. 对称二叉树

Problem: 101. 对称二叉树 文章目录 思路解题方法Code结果 思路 看到这个题&#xff0c;想到的解题方法是使用递归实现。判断二叉树是否对称&#xff0c;需要判断根节点的左子树和右子树是否对称。所以从根节点开始&#xff0c;递归判断左子树的左节点是否和右子树的右节点是否…

【实战】十一、看板页面及任务组页面开发(一) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十三)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…

NPM与外部服务的集成(上)

目录 1、关于访问令牌 1.1 关于传统令牌 1.2 关于粒度访问令牌 2、创建和查看访问令牌 2.1 创建访问令牌 在网站上创建传统令牌 在网站上创建粒度访问令牌 使用CLI创建令牌 CIDR限制令牌错误 查看访问令牌 在网站上查看令牌 在CLI上查看令牌 令牌属性 1、关于访问令…

根据二叉树创建字符串

题目:给你二叉树的根节点 root &#xff0c;请你采用前序遍历的方式&#xff0c;将二叉树转化为一个由括号和整数组成的字符串&#xff0c;返回构造出的字符串。 空节点使用一对空括号对 "()" 表示&#xff0c;转化后需要省略所有不影响字符串与原始二叉树之间的一对…