目录
注:使用案例写在文章最后。
1.spring内置的缓存
1.1概述
Spring为我们提供了几个注解来支持Spring Cache。其核心主要是@Cacheable和@CacheEvict。使用@Cacheable标记的方法在执行后Spring Cache将缓存其返回结果,而使用@CacheEvict标记的方法会在方法执行前或者执行后移除Spring Cache中的某些元素。下面我们将来详细介绍一下Spring基于注解对Cache的支持所提供的几个注解。
1.2.@Cacheable
@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。
1.2.1 value属性指定Cache名称
value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。
@Cacheable(“cache1”)//Cache是发生在cache1上的
public User find(Integer id) {
return null;
}
@Cacheable({“cache1”, “cache2”})//Cache是发生在cache1和cache2上的
public User find(Integer id) {
return null;
}
1.2.2 使用key属性自定义key
key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。我们这里先来看看自定义策略,至于默认策略会在后文单独介绍。
自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。下面是几个使用参数作为key的示例。
@Cacheable(value=”users”, key=”#id”)
public User find(Integer id) {
return null;
}
@Cacheable(value=”users”, key=”#p0”)
public User find(Integer id) {
return null;
}
@Cacheable(value=”users”, key=”#user.id”)
public User find(User user) {
return null;
}
@Cacheable(value=”users”, key=”#p0.id”)
public User find(User user) {
return null;
}
除了上述使用方法参数作为key之外,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 |
当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。如:
@Cacheable(value={“users”, “xxx”}, key=”caches[1].name”)
public User find(User user) {
return null;
}
1.2.3 condition属性指定发生的条件
有的时候我们可能并不希望缓存一个方法所有的返回结果。通过condition属性可以实现这一功能。condition属性默认为空,表示将缓存所有的调用情形。其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。如下示例表示只有当user的id为偶数时才会进行缓存。
@Cacheable(value={“users”}, key=”#user.id”, condition=”#user.id%2==0”)
public User find(User user) {
System.out.println(“find user by user “ + user);
return user;
}
1.3. @CachePut
在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
@CachePut(“users”)//每次都会执行方法,并将结果存入指定的缓存中
public User find(Integer id) {
return null;
}
1.4. @CacheEvict
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。下面我们来介绍一下新出现的两个属性allEntries和beforeInvocation。
1.4.1 allEntries属性
allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。
@CacheEvict(value=”users”, allEntries=true)
public void delete(Integer id) {
System.out.println(“delete user by id: “ + id);
}
1.4.2 beforeInvocation属性
清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。
@CacheEvict(value=”users”, beforeInvocation=true)
public void delete(Integer id) {
System.out.println(“delete user by id: “ + id);
}
其实除了使用@CacheEvict清除缓存元素外,当我们使用Ehcache作为实现时,我们也可以配置Ehcache自身的驱除策略,其是通过Ehcache的配置文件来指定的。由于Ehcache不是本文描述的重点,这里就不多赘述了,想了解更多关于Ehcache的信息,请查看我关于Ehcache的专栏。
1.4.3 CacheEvict同时失效多个缓存
失效一个缓存:
同时失效多个缓存:
失效指定缓存:
待补充,即动态失效某个缓存
1.4.3 CacheEvict使用场景举例
1.清理所有缓存,在value里面把所有缓存都写进来:
@RequestMapping("/clearCacheAll")
@CacheEvict(value = {"testCache2","testCache","testCache3"},allEntries=true)
public void clearCache4() {
System.out.println("清除所有缓存");
}
这么做有点小问题,就是每次新增一个缓存,都要把缓存写到这里的value里面来,但是我暂时不太清楚其他方法。
2.当某个方法执行时清除缓存
比如,有一个统计数量的方法count;
@Cacheable(value="count")
public int count(){
...
}
还有一个新增一条记录的方法insert;
@CacheEvict(value="count")
public Boolean insert(String name){
...
}
此时,count方法被缓存了,但是当insert方法新增一条记录的时候,我们需要count方法能够查出来最新的数据,所以此时在insert方法上去清除count方法对应的缓存即可。
1.5. @Caching
@Caching注解可以让我们在一个方法或者类上同时指定多个Spring Cache相关的注解。其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。
@Caching(cacheable = @Cacheable(“users”), evict = { @CacheEvict(“cache2”),
@CacheEvict(value = “cache3”, allEntries = true) })
public User find(Integer id) {undefined
returnnull;
}
1.6.依赖
<!-- SpringBoot WEB框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--开启 cache 缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- ehcache 缓存 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
1.7.所在目录结构
1.8.使用步骤
1.8.1 引入依赖
<!-- 开启缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
1.8.2 启动类中加入注解开启缓存
@EnableCaching
1.8.3 接口代码
controller和sql代码都是一样的,省略...
service实现如下:
如下 :
getByCodeCache方法上面用注解 @Cacheable,此时第一次调用该方法时就会把该方法的返回值缓存起来,下一次调用该方法时就不会进入该方法内部,直接使用缓存。
getByCodeCache方法内部调用了getByCode方法,getByCode方法里面就是具体的sql方法。实际上只需要把具体的sql逻辑放到有缓存注解的这个方法即可 这里为什么写了两个方法呢?
这是考虑到有的地方可能不需要使用缓存的情况,就直接调用无缓存的这个方法即可。
如果不想要使用缓存,就添加如下属性 condition (这里写false只是举例,前面已经讲过了,此处省略)
这里设计了两个方法,一个有缓存,一个无缓存,实际上可以通过condition属性来动态判断是否需要缓存即可,比如在方法参数中增加一个字段用于校验即可(获取该字段的方法上文也有讲过)。
参考链接:Spring之缓存注解@Cacheable_pengzhisen123的博客-CSDN博客_cacheable
2.spring整合ehcache缓存
2.1 概述
SpringBoot支持很多种缓存方式:redis、guava、ehcahe、jcache等等,这里来介绍整合ehcahe缓存。
如果要使用Ehcache,只需要在pom.xml中增加ehcache依赖,项目中加入ehcache.xml配置文件并在,然后配置文件整合即可,框架只要发现该文件,就会创建EhCache的缓存管理器。
2.2使用步骤
2.2.1 导入依赖
<!--开启 cache 缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--ehcache 缓存 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
2.2.2 新增配置文件
在src/main/resources目录下创建:ehcache.xml
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<!--
Mandatory Default Cache configuration. These settings will be applied to caches
created programmtically using CacheManager.add(String cacheName)
-->
<!--
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
如上配置文件在网上找的解释,timeToIdleSeconds属性解释得不太好,简单的说就是缓存失效时间,当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空。
timeToIdleSeconds 如这个词语本身一样,时间单位是秒。
2.2.3 配置指定缓存
在该配置文件中可以针对某一个缓存进行设置,defaultCache是默认缓存,通过<cache name="CacheName" />来指定某个缓存的配置
如下图的缓存名就是 <cache name=""/>里面对应的name:
2.2.4 spring配置文件整合ehcache
如下在bootstrap.yml文件中配置:
spring:
profiles:
# 当前激活环境
active: dev
# Cache配置
cache:
# 缓存的技术类型
type: ehcache
# 应用程序启动创建缓存的名称
cache-name: ${spring.application.name}
ehcache:
# 配置文件位置
config: classpath:/ehcache.xml
如上 spring整合ehcache就已经完成了,使用方式和之前第一种spring内置的缓存是一样的。