Spring缓存管理


一、spring缓存注解

0、配置

开启基于注解的缓存,使用 @EnableCaching 标识在 SpringBoot 的主启动类上。

配置文件添加:spring.cache.type=simple

1、查缓存@Cacheable

(1)属性介绍

根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。

查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key

其他属性

  • cacheNames/value :用来指定缓存组件的名字,可以是数组的方式,支持指定多个缓存。
  • key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)
  • keyGenerator :key 的生成器。 key 和 keyGenerator 二选一使用
  • cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。
  • condition :可以用来指定符合条件的情况下才缓存
  • unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)
  • sync :是否使用异步模式。默认是方法执行完,以同步的方式将方法返回的结果存在缓存中。

(2)基本使用

下面代码是将 service 业务层的结果作为缓存,首次调用的时候会执行方法内容,再次调用时不执行

当参数为1时,缓存的 key 为 MENU:1,value 为 id:1

@Cacheable(value = "MENU:",key = "#id")
@Override
public String getMenu(String id) {
    System.out.println(id);

    return "id:" + id;
}

当参数是对象时

@Cacheable(value="users", key="#user.id")
public User find(User user) {
    return null;
}

(3)方法执行条件

有的时候我们可能并不希望缓存一个方法所有的返回结果。通过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;
}

2、加缓存@CachePut

使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。

与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key

3、清缓存@CacheEvict

使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上

查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key
allEntries 是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存
beforeInvocation 是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存

清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。

@CacheEvict(value="users", beforeInvocation=true)
public void delete(Integer id) {
      System.out.println("delete user by id: " + id);
}

4、@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) {
   retur null;
}

5、自定义注解

Spring允许我们在配置可缓存的方法时使用自定义的注解,前提是自定义的注解上必须使用对应的注解进行标注。如我们有如下这么一个使用 @Cacheable 进行标注的自定义注解。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Cacheable(value="users")
public @interface MyCacheable {undefined
}

那么在我们需要缓存的方法上使用 @MyCacheable 进行标注也可以达到同样的效果。

@MyCacheable
public User findById(Integer id) {
  System.out.println("find user by id: " + id);
  User user = new User();
  user.setId(id);
  user.setName("Name" + id);
  return user;
}

补充、SpEL 标签

属性名称 描述 示例
methodName 当前方法名 #root.methodName
method 当前方法 #root.method.name
target 当前被调用的对象 #root.target
targetClass 当前被调用的对象的class #root.targetClass
args 当前方法参数组成的数组 #root.args[0]
caches 当前被调用的方法使用的Cache #root.caches[0].name
argument name 方法参数名,可以直接使用 #参数名,也可以用#p0或#a0,0代表参数的索引 #id、#user.id
result 方法执行后的返回值(仅当方法执行后的判断有效) #result

二、CacheManager

1、Cache接口

Cache接口:主要是缓存的增删查功能。

package org.springframework.cache;

public interface Cache {
    String getName();  //缓存的名字

    Object getNativeCache(); //得到底层使用的缓存,如Ehcache

    ValueWrapper get(Object key); //根据key得到一个ValueWrapper,
        然后调用其get方法获取值

    <T> T get(Object key, Class<T> type);//根据key,和value的类型直接获取value

    void put(Object key, Object value);//往缓存放数据

    void evict(Object key);//从缓存中移除key对应的缓存

    void clear(); //清空缓存

    interface ValueWrapper { //缓存值的Wrapper
        Object get(); //得到真实的value
    }
}

由此可见,缓存的对象就是键值对。

默认实现:

  • ConCurrentMapCache:使用java.util.concurrentHashMap实现的Cache。
  • GuavaCache: 对Gguava com.google.common.cache.Cache进行的Wrapper,需要Google Guava 12.0或更高版本。
  • EhCacheCache: 使用Ehcache实现。
  • JCacheCache:对javax.cache.Cache进行的Wrapper。

2、CacheManager接口

CacheManager:Spring提供的缓存管理器,便于管理程序中的多个cache。

public interface CacheManager {
    Cache getCache(String name); //根据Cache名字获取Cache 
    Collection<String> getCacheNames(); //得到所有Cache的名字
}

默认实现:

  • SimpleCacheManager
  • NoOpCacheManager
  • ConcurrentMapCacheManager
  • CompositeCacheManager
  • EhCacheCacheManager
  • RedisCacheManager: 来自spring data redis项目
  • GemfireCacheManager:来自spring data gemfire项目

具体要选择哪个取决于要使用的底层缓存。

另外还提供了CompositeCacheManager用于组合CacheManager,即可以从多个CacheManager轮询得到相应的cache。


  目录