Spring 缓存数据

一、启用声明式缓存

1.1 启用对缓存的支持

Spring对缓存的支持有两种方式:

  • 注解驱动的缓存
  • XML声明的缓存

使用Spring的缓存抽象时,最为通用的方式就是在方法上添加@Cacheable和@CacheEvict注解。
在往bean上添加缓存注解之前,必须要启用Spring对注解驱动缓存的支持。如果我们使用Java配置的话,那么可以在其中的一个配置类上添加@EnableCaching,这样的话就能启用注解驱动的缓存。

1)使用@EnableCaching启用注解驱动的缓存

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.Configuration;

@Configuration
@EnableCaching
public class CachingConfig {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }
}

如果以XML的方式配置应用的话,那么可以使用Spring cache命名空间中的<cache:annotation-driven>元素来启用注解驱动的缓存,通过<bean>元素创建CacheManager。

ConcurrentMapCacheManager缓存管理器是Spring缓存抽象的核心,它能够与多个流行的缓存实现进行集成。ConcurrentMapCacheManager,这个简单的缓存管理器使用java.util.concurrent.ConcurrentHashMap作为其缓存存储。它的缓存存储是基于内存的,所以它的生命周期是与应用关联的。

1.2 配置缓存管理器

Spring 内置缓存管理器实现,如下所示:

  • SimpleCacheManager
  • NoOpCacheManager
  • ConcurrentMapCacheManager
  • CompositeCacheManager
  • EhCacheCacheManager
  • RedisCacheManager(来自于Spring Data Redis项目)
  • GemfireCacheManager(来自于Spring Data GemFire项目)

1.3 使用Ehcache缓存

这个缓存管理器也就是EhCacheCacheManager。

1)设置EhCacheCacheManager

import net.sf.ehcache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
@EnableCaching
public class CachingConfig {

    @Bean
    public CacheManager cm() {
        return new CacheManager();
    }

    @Bean
    public EhCacheCacheManager cacheManager(CacheManager cm) {
        return new EhCacheCacheManager(cm);
    }

    public EhCacheManagerFactoryBean ehcahe() {
        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
        ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("/ehcache.xml"));
        return ehCacheManagerFactoryBean;
    }
}

1.4 使用Redis缓存

在这里插入图片描述

1.5 使用多个缓存管理器

在这里插入图片描述

二、为方法添加注解以支持缓存

2.1 缓存相关注解

下表中的所有注解都能运用在方法或类上。当将其放在单个方法上时,注解所描述的缓存行为只会运用到这个方法上。如果注解放在类级别的话,那么缓存行为就会应用到这个类的所有方法上。

注解描述
@Cacheable表明Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中
@CachePut表明Spring应该将方法的返回值放到缓存中。在方法的调用前并不会检查缓存,方法始终都会被调用
@CacheEvict表明Spring应该在缓存中清除一个或多个条目
@Caching这是一个分组的注解,能够同时应用多个其他的缓存注解

2.2 填充缓存

我们可以看到,@Cacheable和@CachePut注解都可以填充缓存,但是它们的工作方式略有差异。
@Cacheable首先在缓存中查找条目,如果找到了匹配的条目,那么就不会对方法进行调用了。如果没有找到匹配的条目,方法会被调用并且返回值要放到缓存之中。而@CachePut并不会在缓存中检查匹配的值,目标方法总是会被调用,并将返回值添加到缓存之中。
@Cacheable和@CachePut有一些属性是共有的,参见下表。

属性类型描述
valueString[]要使用的缓存名称
conditionStringSpEL
keyStringSpEL表达式,用来计算自定义的缓存key
unlessStringSpEL表达式,如果得到的值是true的话,返回值不会放到缓存之中

1)示例:通过使用@Cacheable,在缓存中存储和获取值

在这里插入图片描述
当findOne()被调用时,缓存切面会拦截调用并在缓存中查找之前以名spittleCache存储的返回值。缓存的key是传递到findOne()方法中的id参数。如果按照这个key能够找到值的话,就会返回找到的值,方法不会再被调用。如果没有找到值的话,那么就会调用这个方法,并将返回值放到缓存之中,为下一次调用findOne()方法做好准备。
当为接口方法添加注解后,@Cacheable注解会被接口的所有子类继承。

2)将值放到缓存之中

@Cacheable会条件性地触发对方法的调用,这取决于缓存中是不是已经有了所需要的值,对于所注解的方法,@CachePut采用了一种更为直接的流程。带有@CachePut注解的方法始终都会被调用,而且它的返回值也会放到缓存中。这提供一种很便利的机制,能够让我们在请求之前预先加载缓存。@CachePut一般用于缓存更新。

3)自定义缓存key

@Cacheable和@CachePut都有一个名为key属性,这个属性能够替换默认的key,它是通过一个SpEL表达式计算得到的。
Spring提供了多个用来定义缓存规则的SpEL扩展:

表达式描述
#root.args传递给缓存方法的参数,形式为数组
#root.caches该方法执行时所对应的缓存,形式为数组
#root.target目标对象
#root.targetClass目标对象的类,是 #root.target.class 的简写形式
#root.method缓存方法
#root.methodName缓存方法的名字,是 #root.method.name 的简写形式
#result方法调用的返回值(不能用在 @Cacheable 注解上)
#Argument任意的方法参数名(如 #argName )或参数索引(如 #a0 或 #p0 )

示例:在这里插入图片描述

4)条件化缓存

通过为方法添加Spring的缓存注解,Spring就会围绕着这个方法创建一个缓存切面。但是,在有些场景下我们可能希望将缓存功能关闭。

@Cacheable和@CachePut提供了两个属性用以实现条件化缓存:unless和condition,这两个属性都接受一个SpEL表达式。如果unless属性的SpEL表达式计算结果为true,那么缓存方法返
回的数据就不会放到缓存中。与之类似,如果condition属性的SpEL表达式计算结果为false,那么对于这个方法缓存就会被禁用。

表面上来看,unless和condition属性做的是相同的事情。但是,这里有一点细微的差别。unless属性只能阻止将对象放进缓存,但是在这个方法调用的时候,依然会去缓存中进行查找,如果找到了匹配的值,就会返回找到的值。与之不同,如果condition的表达式计算结果为false,那么在这个方法调用的过程中,缓存是被禁用的。就是说,不会去缓存进行查找,同时返回值也不会放进缓存中。
在这里插入图片描述

2.3 移除缓存条目

@CacheEvict并不会往缓存中添加任何东西。相反,如果带有@CacheEvict注解的方法被调用的话,那么会有一个或更多的条目会在缓存中移除。
那么在什么场景下需要从缓存中移除内容呢?当缓存值不再合法时,我们应该确保将其从缓存中移除,这样的话,后续的缓存命中就不会返回旧的或者已经不存在的值,其中一个这样的场景就是数据被删除掉了。这样的话,SpittleRepository的remove()方法就是使用@CacheEvict的绝佳选择:
在这里插入图片描述

1) @CacheEvict的属性

属性类型描述
valueString[]要使用的缓存名称
keyStringSpEL表达式,用来计算自定义的缓存key
conditionStringSpEL表达式,如果得到的值是false的话,缓存不会应用到方法调用上
allEntriesboolean如果为true的话,特定缓存的所有条目都会被移除掉
beforeInvocationboolean如果为true的话,在方法调用之前移除条目。如果 为 false (默认值)的话,在方法成功调用之后再移除条目
三、使用XML声明缓存

3.1 使用XML配置的原因

  • 你可能会觉得在自己的源码中添加Spring的注解有点不太舒服;
  • 你需要在没有源码的bean上应用缓存功能。

Spring的cache命名空间提供了使用XML声明缓存规则的方法,可以作为面向注解缓存的替代方案。因为缓存是一种面向切面的行为,所以cache命名空间会与Spring的aop命名空间结合起来使用,用来声明缓存所应用的切点在哪里。

3.2 Spring的cache命名空间

元素描述
<cache:annotation-driven>启用注解驱动的缓存。等同于Java配置中的 @EnableCaching
<cache:advice>定义缓存通知(advice)。结合 <aop:advisor> ,将通知应用到切点上
<cache:caching>在缓存通知中,定义一组特定的缓存规则
<cache:cacheable>指明某个方法要进行缓存。等同于 @Cacheable 注解
<cache:cache-put>指明某个方法要填充缓存,但不会考虑缓存中是否已有匹配的值。等同于 @CachePut 注解
<cache:cache-evict>指明某个方法要从缓存中移除一个或多个条目,等同于@CacheEvict 注解

3.3 使用XML配置缓存

在这里插入图片描述
<cache:cacheable>、<cache:cache-put>和<cache:cache-evict>元素都引用了同一个名
为spittleCache的缓存。为了消除这种重复,我们可以在<cache:caching>元素上指明缓存的名字:在这里插入图片描述

<cache:caching>有几个可以供<cache:cacheable>、<cache:cache-put>和<cache:cache-evict>共享的属性,包括:

  • cache:指明要存储和获取值的缓存;
  • key:SpEL表达式,用来得到缓存的key(默认为方法的参数);
  • method:要缓存的方法名。

除此之外,<cache:cacheable>和<cache:cache-put>还有一个unless属性,可以为这个可选的属性指定一个SpEL表达式,如果这个表达式的计算结果为true,那么将会阻止将返回值放到缓存之中。

<cache:cache-evict>元素还有几个特有的属性:

  • all-entries:如果是true的话,缓存中所有的条目都会被移除掉。如果是false的话,只有匹配key的条目才会被移除掉。
  • before-invocation:如果是true的话,缓存条目将会在方法调用之前被移除掉。如果是false的话,方法调用之后才会移除缓存。

all-entries和before-invocation的默认值都是false。这意味着在使用<cache:cache-evict>元素且不配置这两个属性时,会在方法调用完成后只删除一个缓存条目。要删除的条目会通过默认的key(基于方法的参数)进行识别,当然也可以通过为名为key的属性设置一个SpEL表达式指定要删除的key。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

书香水墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值