【思维导图】spring cache-缓存作用

合集下载

Spring缓存注解(@Cacheable@CachePut@CacheEvict@Cac。。。

Spring缓存注解(@Cacheable@CachePut@CacheEvict@Cac。。。

Spring缓存注解(@Cacheable@CachePut@CacheEvict@Cac。

Spring缓存注解 缓存⼤家应该不会陌⽣吧,像⼤家熟知的redis、memcached都是现在所流⾏的⽤与缓存数据的nosql,叫nosql的原因在于他们不是像我们jpa那样将数据存到磁盘中,他们主要是将数据存到内存中,然后我们访问数据的时候直接从内存加载出来,通过这样的⽅法来提⾼我们程序的运⾏效率。

⾄于redis等他们具体如何运转的我就不⼀⼀介绍了.。

如果我们做web开发的话,那么应该都会接触到spring的东西,正是因为有spring的存在,才使我们的开发效率更快,⽽我们本节主要讲的就是基于spring帮我们实现的缓存注解。

我们回想⼀下,在我们⽇常的开发中,其实我们所做的后台其实⼤多对数据的操作,⽽我们操作的数据基本上都是需要存到jpa数据库中,我们前端显⽰的时候就要通过查询数据库来将数据查询出来并传送给前端。

如果并发⼩的话,其实我们是⽆需关注这个事情,但是如果你的并发量很⼤的时候,你频繁的访问数据库,这个开销是很⼤的,⽽在我们⽇常开发的项⽬中,其实是读取数据的频率是⼤于写的频率的,那么我们为何不将读取的数据放到缓存中,然后下⼀次查询的时候,会先去缓存查看是否有数据,如果没有的话在去查询数据库。

这样的话,⼀些共有的数据是不是⼤家访问的话就不会⼀⼀查询数据库了,其次是因为从内存中读取数据是远远快于磁盘读取的。

当然,这种缓存的⼯具,spring也已经帮我们整合好了。

⽽接下来也会基于以下⼏个注解来讲是如何进⾏缓存的。

@Cacheable@CachePut@CacheEvict@Caching@Cacheable 这个注解的作⽤是负责将返回的数据进⾏缓存,当我们第⼀次访问的时候,会将查出来的数据先缓存到redis中,当之后再发起访问的时候,会先去查看缓存中是否存在该条数据,如果存在的话就直接从缓存拿取该条数据。

使用spring自带的cache

使用spring自带的cache

结合测试类发现,显然第二次调用没有进service实现类5、下面补充几个概念@Cacheable、@CachePut、@CacheEvict 注释介绍通过上面的例子,我们可以看到 spring cache 主要使用两个注释标签,即 @Cacheable、@CachePut 和 @CacheEvict,我们总结一下其作用和配置方法。

表 1. @Cacheable 作用和配置方法@Cacheable 的作用主要针对方法配置,能够根据方法的请求参数对其结果进行缓存@Cacheable主要的参数value缓存的名称,在 spring 配置文件中定义,必须指定至少一个例如:@Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”}key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合例如:@Cacheable(value=”testcache”,key=”#u serName”)condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存例如:@Cacheable(value=”testcache”,condition =”#userName.length()>2”)表 2. @CachePut 作用和配置方法@CachePut 的作用主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用@CachePut主要的参数value缓存的名称,在 spring 配置文件中定义,必须指定至少一个例如:@Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”}key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合例如:@Cacheable(value=”testcache”,key=”#us erName”)condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存例如:@Cacheable(value=”testcache”,condition =”#userName.length()>2”)表 3. @CacheEvict 作用和配置方法@CachEvict 的作用主要针对方法配置,能够根据一定的条件对缓存进行清空@CacheEvict 主要的参数value缓存的名称,在 spring 配置文件中定义,必须指定至少一个例如:@CachEvict(value=”mycach e”) 或者@CachEvict(value={”cache1”,”cache2”}key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合例如:@CachEvict(value=”testcach e”,key=”#userName”)condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存例如:@CachEvict(value=”testcach e”,condition=”#userName.lengt h()>2”)allEntries是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存例如:@CachEvict(value=”testcach e”,allEntries=true)beforeInvoca tion 是否在方法执行前就清空,缺省为 false ,如果指定为 true ,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存例如:@CachEvict(value=”testcach e”,beforeInvocation=true)。

使用SpringCache设置缓存条件操作

使用SpringCache设置缓存条件操作

使⽤SpringCache设置缓存条件操作⽬录Spring Cache设置缓存条件原理@Cacheable的常⽤属性及说明Root对象@CachePut的常⽤属性同@CacheableCache缓存配置1、pom.xml2、Ehcache配置⽂件3、配置类4、⽰例Spring Cache设置缓存条件原理从Spring3.1开始,Spring框架提供了对Cache的⽀持,提供了⼀个对缓存使⽤的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存⽅法的返回对象的作⽤。

提供的主要注解有@Cacheable、@CachePut、@CacheEvict和@Caching,具体见下表:注解说明@Cacheable 可以标注在类或⽅法上:标注在⽅法上表⽰该⽅法⽀持数据缓存;标在类上表⽰该类的所有⽅法都⽀持数据缓存。

具体功能:在执⾏⽅法体之前,检查缓存中是否有相同key值的缓存存在,如果存在对应的缓存,直接返回缓存中的值;如果不存在对应的缓存,则执⾏相应的⽅法体获取数据,并将数据存储到缓存中。

@CachePut可以标注在类或⽅法上,表⽰⽀持数据缓存。

具体功能:在⽅法执⾏前不会检查缓存中是否存在相应的缓存,⽽是每次都会执⾏⽅法体,并将⽅法执⾏结果存储到缓存中,如果相应key值的缓存存在,则更新key对应的value值。

@CacheEvict可以标注在类或⽅法上,⽤于清除相应key值的缓存。

@Caching可以标注在类或⽅法上,它有三个属性cacheable、put、evict分别⽤于指定@Cacheable、@CachePut和@CacheEvict当需要在类上或⽅法上同时使⽤多个注解时,可以使⽤@Caching,如:@Caching(cacheable=@Cacheable("User"), evict = {@CacheEvict("Member"), @CacheEvict(value = "Customer", allEntries = true)})@Cacheable的常⽤属性及说明如下表所⽰:@Cacheable属性说明key表⽰缓存的名称,必须指定且⾄少要有⼀个值,⽐如:@Cacheable(value=“Dept”)或@Cacheable(value={“Dept”,“Depts”})condition表⽰是否需要缓存,默认为空,表⽰所有情况都会缓存。

SpringCache的简介和使用

SpringCache的简介和使用

SpringCache的简介和使⽤1、简介Spring 从 3.1 开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接⼝来统⼀不同的缓存技术;并⽀持使⽤ JCache(JSR-107)注解简化我们开发Cache 接⼝为缓存的组件规范定义,包含缓存的各种操作集合; Cache 接⼝下 Spring 提供了各种 xxxCache 的实现;如 RedisCache ,EhCacheCache , ConcurrentMapCache 等;每次调⽤需要缓存功能的⽅法时,Spring 会检查检查指定参数的指定的⽬标⽅法是否已经被调⽤过;如果有就直接从缓存中获取⽅法调⽤后的结果,如果没有就调⽤⽅法并缓存结果后返回给⽤户。

下次调⽤直接从缓存中获取2、整合SpringCache简化缓存开发1)引⼊依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>2)添加配置spring.cache.type=redis3)测试使⽤缓存@Cacheable 触发将数据保存到缓存的操作@CacheEvict 将数据从缓存删除@CachePut 不影响⽅法执⾏更新缓存@Caching 组合以上多个操作@CacheConfig 在类级别,共享缓存的相同配置①、主启动类上添加 @EnableCache注解,开启缓存功能②、只需要使⽤注解就可以完成缓存操作当⽅法的结果需要缓存到数据库,在⽅法上加上 @CacheEnable注解/*1、每⼀个需要缓存的数据,我们都要来指定要放到哪个名字的缓存。

深度理解springboot集成cache缓存之源码解析

深度理解springboot集成cache缓存之源码解析

深度理解springboot集成cache缓存之源码解析⼀、案例准备1.创建数据表(employee表)2.创建Employee实体类封装数据库中的数据@AllArgsConstructor@NoArgsConstructor@Data@ToStringpublic class Employee {private Integer id;private String lastName;private String email;private Integer gender; //1.男 2.⼥private Integer dId;}3.编写EmployeeMapper接⼝(DAO测通)@Mapperpublic interface EmployeeMapper {@Select("select * from employee where id=#{id}")Employee getEmpById(Integer id);}4.编写EmployeeService接⼝及其EmployeeServiceImpl实现类@Servicepublic class EmployeeServiceImpl implements EmployeeService {@Autowiredprivate EmployeeMapper employeeMapper;@Override@Cacheable(cacheNames = "emp",key = "#id",condition = "#id>0")public Employee getEmp(Integer id) {System.out.println("正在查询id为"+id+"号的员⼯");Employee emp = employeeMapper.getEmpById(id);return emp;}}5.编写EmployeeController类@RestControllerpublic class EmpController {@Autowiredprivate EmployeeService employeeService;@GetMapping("/emp/{id}")public Employee getEmployee(@PathVariable("id") Integer id){Employee emp = employeeService.getEmp(id);return emp;}}6.启动访问http://localhost:8080/emp/1成功!-----------------------------------------------分割线-------------------------------------------------------------⼆、⼯作原理分析1.查看springboot启动时,导⼊了哪些缓存组件通过以往springboot相关的⾃动配置类可知与缓存相关的⾃动配置类为CacheAutoConfiguration@Import:向容器中导⼊⼀些组件(通常导⼊的选择器以ImportSelector结尾) ctrl+右键查看CacheConfigurationImportSelector源码static class CacheConfigurationImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {CacheType[] types = CacheType.values();String[] imports = new String[types.length];for (int i = 0; i < types.length; i++) {imports[i] = CacheConfigurations.getConfigurationClass(types[i]);}return imports;}}}打上断点,debug模式下运⾏放⾏,查看return imports的结果导⼊的组件如下* "org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration"* "org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration"2.是哪个缓存配置类⽣效呢?根据当前的场景进⾏分析有两种⽅法可以得出哪个缓存配置类⽣效第⼀种:源码分析(该⽅法只做简单说明)随便打开⼀个缓存配置类,例如第⼀个GenericCacheConfiguration,查看源码如下@Configuration(proxyBeanMethods = false)@ConditionalOnBean(Cache.class)@ConditionalOnMissingBean(CacheManager.class)@Conditional(CacheCondition.class)class GenericCacheConfiguration {@BeanSimpleCacheManager cacheManager(CacheManagerCustomizers customizers, Collection<Cache> caches) {SimpleCacheManager cacheManager = new SimpleCacheManager();cacheManager.setCaches(caches);return customizers.customize(cacheManager);}}根据类上的@ConditionalOnBean(Cache.class)@ConditionalOnMissingBean(CacheManager.class)@Conditional(CacheCondition.class)注解进⾏判断该类是否⽣效这些都是@Conditional注解的衍⽣注解,该注解是Spring4新推出的注解,判断是否满⾜某种条件,如果满⾜则给容器注册bean第⼆种:查看⾃动配置报告在application.properties配置⽂件中添加debug=true运⾏发现这⼏个组件中只有SimpleCacheConfiguration⽣效了3.分析核⼼类的作⽤进去查看SimpleCacheConfiguration的源码@Configuration(proxyBeanMethods = false)@ConditionalOnMissingBean(CacheManager.class)@Conditional(CacheCondition.class)class SimpleCacheConfiguration {@BeanConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,CacheManagerCustomizers cacheManagerCustomizers) {ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();List<String> cacheNames = cacheProperties.getCacheNames();if (!cacheNames.isEmpty()) {cacheManager.setCacheNames(cacheNames);}return cacheManagerCustomizers.customize(cacheManager);}}可以看出给容器中注册了⼀个ConcurrentMapCacheManager缓存管理器查看源码分析创建Cache的具体细节这⼀段代码是创建Cache的核⼼#⾸先通过该类中的cacheMap属性获取缓存,参数为缓存名字(key-value)#然后进⾏判断,如果cache为null,则上锁;再次获取如果为null,则根据本类中的createConcurrentMapCache⽅法创建Cache,然后将其放到缓存中protected Cache createConcurrentMapCache(String name) {SerializationDelegate actualSerialization = this.isStoreByValue() ? this.serialization : null;return new ConcurrentMapCache(name, new ConcurrentHashMap(256), this.isAllowNullValues(), actualSerialization);}}可以看出返回时创建了ConcurrentMapCache对象,进去查看源码lookup⽅法的作⽤是从缓存中获取数据put⽅法的作⽤是是保存数据到缓存中⾃此我们可以猜⼀下,ConcurrentMapCache该类的作⽤就是对缓存中的数据进⾏操作,如果缓存中没有数据,则从数据库查询,⼀并放到缓存中总的来说ConcurrentMapCacheManager类的作⽤就是,先判断是否有某缓存,如果没有就创建该缓存,ConcurrentMapCache类从数据库中进⾏查询,⼀并将数据存储到ConcurrentMap集合中4.运⾏流程根据上⾯打上的四个断点,debug模式下启动发现程序刚开始并没有⾛EmployeeServiceImpl的断点,⽽是⾛到了这个getCache⽅法,寻找name=emp的缓存因为没有名为emp的缓存,所以会创建名为emp的缓存,继续放⾏使⽤key去缓存中查找内容(key默认是⽅法的参数,浏览器访问的是1号员⼯信息,id=1即key=1),size=0,缓存中的数据为空继续放⾏直接调⽤业务⽅法去数据库中查询数据了,这是为什么呢,因为上个步骤在缓存中没有查询到数据,所以需要向数据库中要数据;继续放⾏上⼀步从数据库中查询出数据之后,将数据传回前端页⾯展⽰并使⽤put⽅法将其放⼊到缓存中此时缓存中已经有数据了,当我再次debug运⾏就不会再从数据库中查询数据了该博客仅为了记录⾃⼰的学习过程,理清技术点思路。

Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

Spring缓存注解@Cacheable、@CacheEvict、@CachePut使⽤从3.1开始,Spring引⼊了对Cache的⽀持。

其使⽤⽅法和原理都类似于Spring对事务管理的⽀持。

Spring Cache是作⽤在⽅法上的,其核⼼思想是这样的:当我们在调⽤⼀个缓存⽅法时会把该⽅法参数和返回结果作为⼀个键值对存放在缓存中,等到下次利⽤同样的参数来调⽤该⽅法时将不再执⾏该⽅法,⽽是直接从缓存中获取结果进⾏返回。

所以在使⽤Spring Cache的时候我们要保证我们缓存的⽅法对于相同的⽅法参数要有相同的返回结果。

使⽤Spring Cache需要我们做两⽅⾯的事:n 声明某些⽅法使⽤缓存n 配置Spring对Cache的⽀持和Spring对事务管理的⽀持⼀样,Spring对Cache的⽀持也有基于注解和基于XML配置两种⽅式。

下⾯我们先来看看基于注解的⽅式。

1 基于注解的⽀持Spring为我们提供了⼏个注解来⽀持Spring Cache。

其核⼼主要是@Cacheable和@CacheEvict。

使⽤@Cacheable标记的⽅法在执⾏后Spring Cache将缓存其返回结果,⽽使⽤@CacheEvict标记的⽅法会在⽅法执⾏前或者执⾏后移除Spring Cache中的某些元素。

下⾯我们将来详细介绍⼀下Spring基于注解对Cache的⽀持所提供的⼏个注解。

1.1 @Cacheable@Cacheable可以标记在⼀个⽅法上,也可以标记在⼀个类上。

当标记在⼀个⽅法上时表⽰该⽅法是⽀持缓存的,当标记在⼀个类上时则表⽰该类所有的⽅法都是⽀持缓存的。

对于⼀个⽀持缓存的⽅法,Spring会在其被调⽤后将其返回值缓存起来,以保证下次利⽤同样的参数来执⾏该⽅法时可以直接从缓存中获取结果,⽽不需要再次执⾏该⽅法。

Spring在缓存⽅法的返回值时是以键值对进⾏缓存的,值就是⽅法的返回结果,⾄于键的话,Spring⼜⽀持两种策略,默认策略和⾃定义策略,这个稍后会进⾏说明。

Spring为何要用三级缓存来解决循环依赖问题

Spring为何要用三级缓存来解决循环依赖问题

Spring为何要⽤三级缓存来解决循环依赖问题我们都知道Spring为了解决循环依赖使⽤了三级缓存Spring三级缓存⼀级缓存singletonObjects⽤于保存BeanName和创建bean实例之间的关系,beanName -> bean instanceprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);⼆级缓存earlySingletonObjects保存提前曝光的单例bean对象private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);三级缓存singletonFactories保存beanName和创建bean实例之间的关系,与singletonObjects不同的地⽅在于,当⼀个单例bean被放到这⾥⾯后,bean在创建过程中,可以通过getBean⽅法获取到,⽬的是⽤来检测循环引⽤private final Map<String, Object> singletonFactories = new HashMap(16);在创建bean的时候,⾸先从缓存中获取单例的bean,这个缓存就是singletonObjects,如果获取不到且bean正在创建中,就再从earlySingletonObjects中获取,如果还是获取不到且允许从singletonFactories中通过getObject拿到对象,就从singletonFactories中获取,如果获取到了就存⼊earlySingletonObjects并从singletonFactories中移除。

为什么要使⽤三级缓存?⼀级缓存⾸先我们看看⼀级缓存⾏不⾏,如果只留第⼀级缓存,那么单例的Bean都存在singletonObjects 中,Spring循环依赖主要基于Java引⽤传递,当获取到对象时,对象的field或者属性可以延后设置,理论上可以,但是如果延后设置出了问题,就会导致完整的Bean和不完整的Bean都在⼀级缓存中,这个引⽤时就有空指针的可能,所以⼀级缓存不⾏,⾄少要有singletonObjects 和earlySingletonObjects 两级。

springcache抽象详解

springcache抽象详解

Spring Cache抽象详解缓存简介缓存,我的理解是:让数据更接近于使用者;工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存);缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/IO)的且对于相同的请求有相同的计算结果的数据。

如CPU--L1/L2--内存--磁盘就是一个典型的例子,CPU需要数据时先从L1/L2中读取,如果没有到内存中找,如果还没有会到磁盘上找。

还有如用过Maven的朋友都应该知道,我们找依赖的时候,先从本机仓库找,再从本地服务器仓库找,最后到远程仓库服务器找;还有如京东的物流为什么那么快?他们在各个地都有分仓库,如果该仓库有货物那么送货的速度是非常快的。

缓存命中率即从缓存中读取数据的次数与总读取次数的比率,命中率越高越好:命中率= 从缓存中读取次数/ (总读取次数[从缓存中读取次数+ 从慢速设备上读取的次数])Miss率= 没有从缓存中读取的次数/ (总读取次数[从缓存中读取次数+ 从慢速设备上读取的次数])这是一个非常重要的监控指标,如果做缓存一定要健康这个指标来看缓存是否工作良好;缓存策略Eviction policy移除策略,即如果缓存满了,从缓存中移除数据的策略;常见的有LFU、LRU、FIFO:FIFO(First In First Out):先进先出算法,即先放入缓存的先被移除;LRU(Least Recently Used):最久未使用算法,使用时间距离现在最久的那个被移除;LFU(Least Frequently Used):最近最少使用算法,一定时间段内使用次数(频率)最少的那个被移除;TTL(Time To Live )存活期,即从缓存中创建时间点开始直到它到期的一个时间段(不管在这个时间段内有没有访问都将过期)TTI(Time To Idle)空闲期,即一个数据多久没被访问将从缓存中移除的时间。

到此,基本了解了缓存的知识,在Java中,我们一般对调用方法进行缓存控制,比如我调用"findUserById(Long id)",那么我应该在调用这个方法之前先从缓存中查找有没有,如果没有再掉该方法如从数据库加载用户,然后添加到缓存中,下次调用时将会从缓存中获取到数据。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档