Spring缓存数据

1.启用缓存

Spring对缓存的支持有两种方式:
    1.注解驱动的缓存
    2.XML声明的缓存

使用Spring的缓存抽象时,最为通用的方式就是在方法上添加@Cacheable和@CacheEvict注解。

在本例中,声明了ConcurrentMapCacheManager,这个简单的缓存管理器使用java.util.concurrent.ConcurrentHashMap作为其缓存存储。

如果使用Java配置的话,那么可以在其中的一个配置类上添加@EnableCaching,这样的话就能启用注解驱动的缓存。

Spring缓存数据_第1张图片

如果以XML的方式配置应用的话,那么可以使用Spring cache命名空间中的元素来启用注解驱动的缓存。

Spring缓存数据_第2张图片

    在本质上,@EnableCaching和的工作方式是相同的。它们都会创建一个切面(aspect)并触发Spring缓存注解的切点(pointcut)。根据所使用的注解以及缓存的状态,这个切面会从缓存中获取数据,将数据添加到缓存之中或者从缓存中移除某个值。

配置缓存管理器

Spring 3.1内置了五个缓存管理器实现,如下所示:
1.SimpleCacheManager
2.NoOpCacheManager
3.ConcurrentMapCacheManager
4.CompositeCacheManager
5.EhCacheCacheManager

Spring 3.2引入了另外一个缓存管理器,这个管理器可以用在基于JCache(JSR-107)的缓存提供商之中。除了核心的Spring框架,Spring Data又提供了两个缓存管理器:

1.RedisCacheManager(来自于Spring Data Redis项目)
2.GemfireCacheManager(来自于Spring Data GemFire项目)

使用Ehcache缓存

Spring缓存数据_第3张图片

    cacheManager()方法创建了一个EhCacheCacheManager的实例,这是通过传入Ehcache CacheManager实例实现的。需要明确的是,EhCache的CacheManager要被注入到Spring的EhCacheCacheManager(Spring CacheManager的实现)之中。

    我们需要使用EhCache的CacheManager来进行注入,所以必须也要声明一个CacheManager bean。为了对其进行简化,Spring提供了EhCacheManager-FactoryBean来生成EhCache的CacheManager。方法ehcache()会创建并返回一个EhCacheManagerFactoryBean实例。因为它是一个工厂bean(也就是说,它实现了Spring的FactoryBean接口),所以注册在Spring应用上下文中的并不是EhCacheManagerFactoryBean的实例,而是CacheManager的一个实例,因此适合注入到EhCacheCacheManager之中。

    除了在Spring中配置的bean,还需要有针对EhCache的配置。EhCache为XML定义了自己的配置模式,我们需要在一个XML文件中配置缓存,该文件需要符合EhCache所定义的模式。在创建EhCacheManagerFactoryBean的过程中,需要告诉它EhCache配置文件在什么地方。在这里通过调用setConfigLocation()方法,传入ClassPath-Resource,用来指明EhCache XML配置文件相对于根类路径(classpath)的位置。

ehcache.xml文件的内容,不同的应用之间会有所差别,但是至少需要声明一个最小的缓存。例如,如下的EhCache配置声明一个名为spittleCache的缓存,它最大的堆存储为50MB,存活时间为100秒。
Spring缓存数据_第4张图片

使用redis缓存

    Spring Data Redis提供了RedisCacheManager,这是CacheManager的一个实现。RedisCacheManager会与一个Redis服务器协作,并通过RedisTemplate将缓存条目存储到Redis中。

配置如下所示:

Spring缓存数据_第5张图片

使用多个缓存管理器

使用超过一个缓存管理器的话,那么可以使用Spring的CompositeCacheManager。

CompositeCacheManager要通过一个或更多的缓存管理器来进行配置,它会迭代这些缓存管理器,以查找之前所缓存的值。如:

Spring缓存数据_第6张图片

当查找缓存条目时,CompositeCacheManager首先会从JCacheCacheManager开始检查JCache实现,然后通过EhCacheCacheManager检查Ehcache,最后会使用RedisCacheManager来检查Redis,完成缓存条目的查找。

2.为方法添加注解 以支持缓存

    Spring的缓存抽象在很大程度上是围绕切面构建的。在Spring中启用缓存时,会创建一个切面,它触发一个或更多的Spring的缓存注解。
    下面的表列出了Spring所提供的缓存注解。表中的所有注解都能运用在方法或类上。当将其放在单个方法上时,注解所描述的缓存行为只会运用到这个方法上。如果注解放在类级别的话,那么缓存行为就会应用到这个类的所有方法上。

Spring缓存数据_第7张图片

填充缓存

@Cacheable和@CachePut注解都可以填充缓存,但是它们的工作方式略有差异。

@Cacheable首先在缓存中查找条目,如果找到了匹配的条目,那么就不会对方法进行调用了。如果没有找到匹配的条目,方法会被调用并且返回值要放到缓存之中。而@CachePut并不会在缓存中检查匹配的值,目标方法总是会被调用,并将返回值添加到缓存之中。

Spring缓存数据_第8张图片

使用方式:

Spring缓存数据_第9张图片

    当findOne()被调用时,缓存切面会拦截调用并在缓存中查找之前以名spittleCache存储的返回值。缓存的key是传递到findOne()方法中的id参数。如果按照这个key能够找到值的话,就会返回找到的值,方法不会再被调用。如果没有找到值的话,那么就会调用这个方法,并将返回值放到缓存之中,为下一次调用findOne()方法做好准备。

    把@Cacheable注解放到接口上,@Cacheable会被所有实现类继承。

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


当save()方法被调用时,它首先会做所有必要的事情来保存Spittle,然后返回的Spittle会被放到spittleCache缓存中。

自定义缓存key

    @Cacheable和@CachePut都有一个名为key属性,这个属性能够替换默认的key,它是通过一个SpEL表达式计算得到的。任意的SpEL表达式都是可行的,但是更常见的场景是所定义的表达式与存储在缓存中的值有关,据此计算得到key。

                                                    定义缓存规则的SpEL扩展


Spring缓存数据_第10张图片
对于save()方法来说,我们需要的键是所返回Spittle对象的id属性。表达式#result能够得到返回的Spittle。借助这个对象,我们可以通过将key属性设置为#result.id来引用id属性:

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

    unless属性只能阻止将对象放进缓存,但是在这个方法调用的时候,依然会去缓存中进行查找,如果找到了匹配的值,就会返回找到的值。与之不同,如果condition的表达式计算结果为false,那么在这个方法调用的过程中,缓存是被禁用的。就是说,不会去缓存进行查找,同时返回值也不会放进缓存中。

    假设对于message属性包含“NoCache”的Spittle对象,我们不想对其进行缓存。为了阻止这样的Spittle对象被缓存起来,可以这样设置unless属性:


为了要对ID小于10的Spittle关闭缓存,可以在@Cacheable上使用condition属性

Spring缓存数据_第11张图片
如果findOne()调用时,参数值小于10,那么将不会在缓存中进行查找,返回的Spittle也不会放进缓存中,就像这个方法没有添加@Cacheable注解一样。

移除缓存条目

如果带有@CacheEvict注解的方法被调用的话,那么会有一个或更多的条目会在缓存中移除。

当remove()调用时,会从缓存中删除一个条目。被删除条目的key与传递进来的spittleId参数的值相等。

@CacheEvict注解的属性,指定了哪些缓存条目应该被移除掉

Spring缓存数据_第12张图片

3.使用XML声明缓存

需要包含的命名空间

Spring缓存数据_第13张图片

Spring缓存数据_第14张图片

使用:

Spring缓存数据_第15张图片

    ,它引用ID为cacheAdvice的通知,该元素将这个通知与一个切点进行匹配,因此建立了一个完整的切面。   在本例中,这个切面的切点会在执行SpittleRepository的任意方法时触发。在元素中,可以包含任意数量的元素,这些元素用来完整地定义应用的缓存规则。

在本例中,只包含了一个元素。这个元素又包含了三个元素和一个元素。每个元素都声明了切点中的某一个方法是支持缓存的。这是与@Cacheable注解同等作用的XML元素。是Spring XML中与@CachePut注解同等作用的元素。它表明一个方法的返回值要填充到缓存之中,但是这个方法本身并不会从缓存中获取返回是Spring XML中与@CachePut注解同等作用的元素。它表明一个方法的返回值要填充到缓存之中,但是这个方法本身并不会从缓存中获取返回值。需要注意的是,元素有一个cache-manager元素,用来指定作为缓存管理器的bean。它的默认值是cacheManager。

元素都引用了同一个名为spittleCache的缓存。为了消除这种重复,我们可以在元素上指明缓存的名字:

Spring缓存数据_第16张图片

有几个可以供共享的属性,包括:
    1.cache:指明要存储和获取值的缓存;
    2·condition:SpEL表达式,如果计算得到的值为false,将会为这个方法禁用缓存;
    3.key:SpEL表达式,用来得到缓存的key(默认为方法的参数);
    4.method:要缓存的方法名。
除此之外,还有一个unless属性,可以为这个可选的属性指定一个SpEL表达式,如果这个表达式的计算结果为true,那么将会阻止将返回值放到缓存之中。
元素还有几个特有的属性:
    1.all-entries:如果是true的话,缓存中所有的条目都会被移除掉。如果是false的话,只有匹配key的条目才会被移除掉。
    2.before-invocation:如果是true的话,缓存条目将会在方法调用之前被移除掉。如果是false的话,方法调用之后才会移除缓存。
    all-entries和before-invocation的默认值都是false。这意味着在使用元素且不配置这两个属性时,会在方法调用完成后只删除一个缓存条目。要删除的条目会通过默认的key(基于方法的参数)进行识别,当然也可以通过为名为key的属性设置一个SpEL表达式指定要删除的key。

参考《Spring实战》


你可能感兴趣的:(Spring)