一、JSR107缓存标准规范:

Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry和Expiry。

  • .CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。
  • .CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
  • .Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
  • .Entry是一个存储在Cache中的key-value对。
  • .Expiry每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置

二、Spring缓存

注:@CachePut用于方法更新,该注解标注的方法每次都会别调用,且结果被缓存

 三、快速使用缓存:

1、开启基于注解缓存@EnableCaching

2、标注缓存注解即可 

@Cacheable
@CacheEvict
@CachePut
/**
     * CacheManager管理多个Cache组件的,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字;
     * 几个属性:
     *     cacheNames/value:指定缓存组件的名字
     *     key:缓存数据使用的key,可以用它来指定。默认是使用方法参数的值
     *               可以编写spel来指定   如:#id;参数id的值 等同于#a0  #p0  #root.args[0]
     *     keyGenerator: key的生成器;可以自己指定key的生成器的组件  如:key="#root.methodName+'['+#id+']'"(key为getArticleById[33])
     *                   key/keyGenerator二选一使用
     *    cacheManager:指定缓存管理器:或者cacheResolver指定  二选一
     *    condition:指定符合条件的情况下才缓存; 
       如:condition="#id>0" 参数id值大于0才进行缓存
            或: condition="#id>0 and #root.methodName eq 'aaa'" * unless:否定缓存:当unless指定条件为true,方法的缓存值就不会缓存;可以获取到结果进行判断 * sync:是否使用异步模式 *
@param id * @return */ @Cacheable(cacheNames = "article") public Article getArticleById(Integer id) { System.out.println("当前查询getArticleById:" + id); return articleMapper.getArticleById(id); }

缓存可用的el表达式

 四、缓存原理:

缓存自动配置类CacheAutoConfiguration

缓存导入的配置类:

0 = "org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration"
1 = "org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration"
2 = "org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration"
3 = "org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration"
4 = "org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration"
5 = "org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration"
6 = "org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration"
7 = "org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration"
8 = "org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration"
9 = "org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration"
10 = "org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration"

默认:SimpleCacheConfiguration生效,给容器中注册了一个cacheManager:ConcurrentMapCacheManager,可以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在concurrentMap中;

核心:

1)使用cacheManager【ConcurrentMapCacheManager】按照名字得到cache【ConcurrentMapCache】

2)key使用keyGenerator生成的,默认是SimpleKeyGenerator

五、@CachePut :调用方法,同时更新缓存

1、与@Cacheable区别:运行时机不一样:@CachePut 先调目标方法,然后缓存结果。@Cacheable先判断是否有该name的cache,没有则创建,再根据key判断缓存中是否有此数据,没有调用目标方法缓存结果,有则直接从缓存中取

2、@CachePut要注意更新缓存时,key要与查询缓存时的key一致,否则不能达到目的 ,另外要注意方法返回结果要和查询结果一样,即value要一样

例:

@CachePut(value = "article",  key="#article.id")
public Article updateArticleById(Article article) {
System.out.println("article更新成功:" + article.getId());
articleMapper.updateArticle(article);
return article;
}

六、@CacheEvict:缓存删除

key:指定要清除的数据

allEntries=true:指定清除这个缓存中所有的数据

beforeInvocation=false:缓存清除是否在方法之前执行

默认缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除

beforeInvocation=true:

代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除

例:

@CacheEvict(value = "article", allEntries=true)
    public void deleteById(Integer id) {
        System.out.println("删除article:" + id);
//        articleMapper.deleteArticleById(id);
    }

 七、@Caching 与@CacheConfig

@Caching定义复杂的缓存规则,实际上是@Cacheable、@CachePut、@CacheEvict的组合注解
@CacheConfig标注在类上,定义公共的缓存属性

 八、整合redis

使用:引入spring-boot-starter-data-redis依赖,配置reids连接yml,注入spring自动配置生成的RedisTemplate(为方便序列化可自定义)

/**
     * Redis常见五大数据类型
     * String(字符串)、List(列表)、Set(集合)、Hash(散列)、ZSet(有序集合)
     * redisTemplate.opsForValue()
     * redisTemplate.opsForList()
     * redisTemplate.opsForSet()
     * redisTemplate.opsForHash()
     * redisTemplate.opsForZSet()
     * @param id
     * @return
     */
    @RequestMapping("/query/{id}")
    public Article queryArticle(@PathVariable("id") Integer id) {
        Article article = articleService.getArticleById(id);
        redisTemplate.opsForValue().set("queryArticle" + id, article);
        return article;
    }
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }
}

 原理:CacheManager===Cache缓存组件来实际给缓存中存取数据

1)、引入redis的starter,容器中保存的是RedisCacheManager:

2)、RedisCacheManager帮我们创建RedisCache来作为缓存组件:

3)、默认保存数据k-v都是object,利用序列化保存;(原因:默认创建的RedisCacheManager操作数据时是使用的RedisTemplate,RedisTemplate默认使用的jdk序列化机制)

4)、自定义CacheManager(默认RedisCacheManager会将cacheName作为key的前缀)