SpringBoot缓存cache的使用

--------------------- 
建议看原文:https://blog.csdn.net/congyihao/article/details/69748108 

 

生效原理
抽象而不是实现
Spring框架中, 缓存服务是一组抽象, 也就是一组API, 由

org.springframework.cache.Cache
org.springframework.cache.CacheManager
抽象. 抽象中并不包含多线程或者多进程处理逻辑, 这些逻辑应该由缓存实现方提供. Spring data工程默认提供了一些实现, 例如ConcurrentHashMap, GemFire, Ehcache等.

通过在方法级别上加@Cacheable等注解, 每当方法被调用的时候, Spring通过AOP的方式拦截方法的执行, 执行缓存的添加, 更新, 删除等操作(取决于注解属性的配置和注解类型).

声明式缓存
在Spring中使用缓存的方式是声明式缓存, 只需要三步配置即可启用:

缓存声明 
在需要缓存的方法上以注解的形式标识.
缓存配置 
显式或隐式配置缓存数据存储后端(Redis, ConcurrentHashMap等).
在@Configuration配置类中加上@EnableCaching, 在应用范围内启用注解.
声明式缓存的类型
共有以下类型:

@Cacheable 查询缓存
@CacheEvict 删除缓存条目
@CachePut 更新缓存条目
@Caching
@CacheConfig
三级缓存策略定制
从上到下, 依次可以进行三次缓存策略的设定, 每一层都会覆盖上层的默认设定:

全局范围的定制: 配置在CacheManager和KeyGenerator中.
类级别的定制: 使用@CacheConfig注解;
方法级别的定制.
Key生成策略
说到底最终还是要以key-value的形式写到后端存储中, 那么Spring的Key生成策略就是值得考虑的. Spring默认的KeyGenerator使用以下算法:

如果没有参数, 返回SimpleKey.EMPTY
如果只有一个参数, 直接返回参数实例.
如果有多个参数, 那么返回一个包含所有参数的SimpleKey.
那么也就是说, 对于cacheNames相同的方法, 如果他们调用时的参数类型和值也相同, 那么就会认为使用的是同一条缓存条目:

@Cacheable(cacheNames = "girl")
public Girl findOne(Integer id) {
    logger.error("方法findOne被调用!");
    return girlRepository.findOne(id);
}

@Cacheable(cacheNames = "girl")
public Girl findOne1(Integer id) {
    logger.error("方法findOne1被调用!");
    return girlRepository.findOne(id);
}

// Test类中
@Test
public void cacheTest() {
    girlService.findOne(14);
    girlService.findOne1(14); // 经测试, 第二条调用不会触发数据库操作
}

缓存添加–@Cacheable的使用
通常用来标识查询缓存, 也就是数据库的select一类的不会改变目标对象状态的情景.

以下是一个使用的例子:

@Cacheable("books")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@Cacheable(cacheNames="books", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)


我们可以通过指定自定义类型的key, 来显式设定缓存的key, 默认是包含方法的所有参数构建的.

同步式缓存
默认缓存策略是不会加锁的, 也就是多线程执行同一个方法的时候, 对于同样参数的调用, 可能仍会被计算多次. 我们可以通过在声明式缓存中配置sync属性, 显式告知CacheManager, 使用同步(阻塞式)策略更新缓存, 也就是多线程下对同一方法的同一参数的调用会被阻塞, 只有一个运行, 其他的线程在锁释放后使用缓存.

@Cacheable(cacheNames="foos", sync="true")
public Foo executeExpensiveOperation(String id) {...}

条件缓存
通过在声明式缓存中添加condition, unless属性, 可以指明缓存只有在符合特定条件下才生效, 并且在执行完后显式排除掉部分结果.

@Cacheable(cacheNames="book", condition="#name.length < 32", unless="#result.hardback")
public Book findBook(String name)

注意:

condition是在方法执行前评估, unless是在方法执行后评估.
关于声明式缓存中能够使用的SpEL类型, 详见文章开头的链接.
缓存更新–@CachePut的使用
通常用来表明该方法的执行应引起缓存条目的更新, 类比于sql的update操作.

@CachePut(cacheNames="book", key="#isbn")
public Book updateBook(ISBN isbn, BookDescriptor descriptor)

缓存清除–@CacheEvict的使用
通常用来表明方法的执行应引起相应缓存条目(或相应缓存主题整体)的清除.

@CacheEvict(cacheNames="books", allEntries=true)
public void loadBooks(InputStream batch)

上面allEntries指明是对相应缓存主题整体或者key对应条目的清除.

多缓存策略–@Caching的使用
允许多个不冲突的缓存策略作为一个缓存策略组同时生效.

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)


统一声明缓存–@CacheConfig的使用
类级别的注解, 用于描述类内方法共享的缓存主题名, 缓存key, CacheManager, CacheResolver等.

@CacheConfig("books")
public class BookRepositoryImpl implements BookRepository {

    @Cacheable
    public Book findBook(ISBN isbn) {...}
}

Spring Boot中对缓存的增强支持
对缓存后端的适配选择更多了, 通常使用的是Redis.

可以通过spring.cache.type显式指定要使用的后端类型, 或者Spring Boot会在路径中自动搜寻缓存后端提供者:

如果找到了, 那么自动创建相应类型的CacheManager实现类, 例如RedisCacheManager.
如果没有找到, 那么默认会使用ConcurrentHashMap作为缓存后端.
如果想要临时关闭缓存, 可以显式指定spring.cache.type=none来关闭缓存操作. 通常用在测试场景中.
定制CacheManager–添加缓存过期时间等
我们也可以通过Java Bean的方式来对Spring Boot自动配置的缓存后端进一步定制, 如设定缓存主题名:

@Bean
public CacheManagerCustomizer cacheManagerCustomizer() {
    return new CacheManagerCustomizer() {
        @Override
        public void customize(ConcurrentMapCacheManager cacheManager) {
            cacheManager.setCacheNames(Arrays.asList("one", "two"));
        }
    };
}

我们可以通过为@Bean添加额外的@Order注解来多次增强配置同一个CacheManager.

一些需要特别说明的点
Spring推荐只在具体类的public方法上使用@Cache*注解 
因为Java中接口的注解是不会被继承到类上的, 所以如果是通过cglib技术进行的动态代理不会触发缓存效果, 此外, 通过字节码织入实现的切面技术也不会触发缓存效果. 所以最好是在具体类的public方法上声明@Cache*.
参考链接:

Spring框架官方文档-Cache部分
Spring Boot Cache章节

 


--------------------- 
原文:https://blog.csdn.net/congyihao/article/details/69748108 
 

你可能感兴趣的:(springBoot)