Spring 缓存详解

Cache is always a key-value storage and Spring caching is not different in this

To enable Spring caching support, we need to take care of following two important points.

  • We need to identify and annotate methods that need to be cached.
  • Cache configuration: Enable caching support

To enable caching annotation, we need to add the annotation @EnableCaching to one the application @Configuration class.

@Configuration
@EnableCaching
public class AppConfig {

    // Cache Manager configurations
}

@EnableCaching 使得post processor检查每一个bean的public方法是否存在caching注解。如果找到这样的注释,则自动创建代理以拦截方法调用并相应地处理缓存行为。

Spring缓存抽象提供了与不同缓存提供者的整合方式,通过定义 CacheManager去控制和管理应用中的Cache。

@Configuration
@EnableCaching
public class AppConfig {

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("product");
    }
}

或许从xml的角度能看得更清楚些:



    
        
            
            
        
    

Spring Boot使用一个简单的实现 ConcurrentHashMap 作为缓存存储。如果应用程序中不存在其他缓存库,则这是默认值。

Spring缓存API提供了一组可供使用的Java注释

Annotation Description
@Cacheable Triggers cache population
@Caching Regroups multiple cache operations
@CacheConfig Shares some common cache-related settings at class-level
@CacheEvict Cache eviction
@CachePut Updates the cache

这些注解并没有严格要求标注在哪里,虽然一般而言会放在service方法上,但实际上放在Controller方法也会起作用。

@Cacheable

简单来说,这个注释用于指示我们希望将此方法的结果存储到缓存中,因此,在后续调用中,返回缓存中的值而无需实际执行该方法。

@Cacheable("products")
public List getProducts() {...}

getProducts()将在实际调用方法之前首先检查缓存“products”,然后缓存结果。此注解允许指定多个名称,以便使用多个缓存。

@Cacheable("baseProducts","varaintProducts")
public List getProducts() {...}

如果两个缓存中包含所需的结果,则直接返回结果不需要调用方法。

@CacheEvict

@CacheEvict(cacheNames="products",allEntries=true,beforeInvocation = false)
public List getProducts() {...}

这个注解与@Cacheable作用相反,用于删除缓存,allEntres则表示删除整个缓存的内容。beforeInvocation能够在方法执行前驱逐缓存,默认为false。

这里必须提一下缓存名字CacheNamesKey的区别,缓存本身有一个名字,这个名字指代的是一整个缓存容器,它可以容纳多个键值对。而用于查找缓存的是Key,Key默认是方法参数的值(默认使用SimpleKeyGenerator生成key)

public static Object generateKey(Object... params) {
  if (params.length == 0) {
    return SimpleKey.EMPTY;
  } else {
    if (params.length == 1) {
      Object param = params[0];
      if (param != null && !param.getClass().isArray()) {
        return param;
      }
    }

    return new SimpleKey(params);
  }
}

可以看到如果只有一个参数,则直接返回。至于有多个参数,实际上返回的是以参数为内容的对象数组的deepHashCode(Arrays类中)

@CachePut

每次都执行方法,把键值对插入缓存,用于更新缓存。

注意不要把@CachePut和@Cacheable用在同一个方法上*

@CacheConfig

类级别的注解,用于集中管理一部分配置。

@CacheConfig("products")
public class ProductService{

    @Cacheable
    public List getProducts() {...}
}

比如这样,相当于指定了所有@Cacheable的名字。

@Caching

用于嵌套多个缓存注解,因为Java不允许多个重名注解。此处不赘述。

自定义Key

@Cacheable(cacheNames="address", key="#customer")
public Address getAddress(final Customer customer)() {...}

@Cacheable(cacheNames="address", key="#customer.id")
public Address getAddress(final Customer customer)() {...}

你甚至还能自己写一个key生成器,此处不赘述

缓存同步

在多线程环境,有可能同一个键值对会被加入/更新多次,我们希望做一定的同步处理。

@Cacheable(value="products",sync=true)
public List getProducts() {...}

此时,计算并且放入缓存的操作会互斥。

条件缓存

@Cacheable(cacheNames="address", condition="#customer.profile.country='US'")
public Address getAddress(final Customer customer)() {...}

@Cacheable(cacheNames="address", unless="#customer.profile.country='US'")
public Address getAddress(final Customer customer)() {...}

unless 在调用方法后进行评估。

你可能感兴趣的:(Spring 缓存详解)