一、首先了解spring自带的注解

  • 首先在启动类需要开启该功能
package com.frame.util;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;@SpringBootApplication
@EnableCaching
@MapperScan("com.frame.util.dao")
public class UtilApplication {public static void main(String[] args) {SpringApplication.run(UtilApplication.class, args);}}

springboot自带注解主要有@Cacheable、@CacheEvict和@CachePut,主要是用AOP代理实现

1.@Cacheable

  1. @Cacheable可以标记在一个类上或者方法上,当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于加上该注解的方法,spring会首先判断该方法相同的参数之前是否有缓存,有的话直接返回,不会走该方法的逻辑;如果没有则需要重新执行该方法,并将方法执行的结果放入缓存。看下面这个例子:
package com.frame.util.service.redis;import com.frame.util.dao.TbPhoneDao;
import com.frame.util.entity.dataObject.TbPhone;
import com.frame.util.entity.vo.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** @Author: towards* @CreateTime: 2022-07-16  11:33* @Description: 缓存注解* @Version: 1.0*/
@Slf4j
@Service
public class CacheAnnotionServiceimpl {private final String phoneKey = "PHONE_";@Resourceprivate TbPhoneDao tbPhoneDao;@Autowiredprivate RedisService redisService;/*** @description: 通过手机名获取手机* @author: towards* @date: 2022/7/16 11:37* @param: name* @return: com.frame.util.vo.ResultVo**/@Cacheable(cacheNames = "phoneCache",key = "#id")public <T> ResultVo getPhone(Integer id) throws Exception {T value = redisService.getKey(keyGenorate(id));if (ObjectUtils.isNotEmpty(value)){// 如果缓存中有,直接返回log.info("query phone from redis");return ResultVo.success(value);}// 缓存中没有,查询数据不为空时,存入缓存TbPhone tbPhone = tbPhoneDao.queryById(id);if (!ObjectUtils.isEmpty(tbPhone)){log.info("query from mysql ,and save to redis");redisService.setKey(keyGenorate(id), tbPhone);return ResultVo.success(tbPhone);}// 缓存和数据库都没有throw new Exception("query phone in redis and mysql is not exist");}/*** @description: 根据id生成redis的key* @author: towards* @date: 2022/7/16 12:12* @param: id* @return: java.lang.String**/public String keyGenorate(Integer id){String redisKey = phoneKey+id;return redisKey;}}
  • 当第一次id=1访问getPhone方法,则getPhone方法会执行内部逻辑,并将结果放入名叫phoneCache的缓存中,下次id=1访问该方法,并不会执行方法内部逻辑。
  • 有一些属性,需要解释一下,方便不同场景使用:
  • cacheNames/value :用来指定缓存组件的名字
  • key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)
  • keyGenerator :key 的生成器。 key 和 keyGenerator 二选一使用
  • cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。
  • condition :可以用来指定符合条件的情况下才缓存
  • unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)
  • sync :是否使用异步模式。
  • 缓存key的获取有多样,支持spel表达式,以下介绍几种,引用博客:https://blog.csdn.net/zl1zl2zl3/article/details/110987968
  • key可以通过keyGenerator生成
  • 自定义KeyGenerator
package com.frame.util.config;import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.lang.reflect.Method;
import java.util.Arrays;/*** @Author: towards* @CreateTime: 2022-07-16  16:45* @Description: TODO* @Version: 1.0*/
@Configuration
public class KeyGenerateConfig {@Bean("myKeyGenerate")public KeyGenerator keyGenerator(){return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {return method.getName()+"["+ Arrays.asList(params).toString()+"]";}};}
}
  • 使用keyGenerate作为缓存键
@Cacheable(cacheNames = "phoneCache",keyGenerator = "myKeyGenerate")public <T> ResultVo getPhone(Integer id) throws Exception {T value = redisService.getKey(keyGenorate(id));if (ObjectUtils.isNotEmpty(value)){// 如果缓存中有,直接返回log.info("query phone from redis");return ResultVo.success(value);}// 缓存中没有,查询数据不为空时,存入缓存TbPhone tbPhone = tbPhoneDao.queryById(id);if (!ObjectUtils.isEmpty(tbPhone)){log.info("query from mysql ,and save to redis");redisService.setKey(keyGenorate(id), tbPhone);return ResultVo.success(tbPhone);}// 缓存和数据库都没有throw new Exception("query phone in redis and mysql is not exist");}

2.@CachePut

  • @CachePut 也可以声明一个方法支持缓存功能。与 @Cacheable 不同的是使用 @CachePut 标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
  • key、value等属性值和@Cacheable相同,key的获取方法也相同
  • 一般使用在更新的场景中,需要更新缓存。以下介绍代码实现:
@CachePut(cacheNames = "phoneCache" , keyGenerator = "myKeyGenerate")public <T> ResultVo getPhone(Integer id) throws Exception {T value = redisService.getKey(keyGenorate(id));if (ObjectUtils.isNotEmpty(value)){// 如果缓存中有,直接返回log.info("query phone from redis");return ResultVo.success(value);}// 缓存中没有,查询数据不为空时,存入缓存TbPhone tbPhone = tbPhoneDao.queryById(id);if (!ObjectUtils.isEmpty(tbPhone)){log.info("query from mysql ,and save to redis");redisService.setKey(keyGenorate(id), tbPhone);return ResultVo.success(tbPhone);}// 缓存和数据库都没有throw new Exception("query phone in redis and mysql is not exist");}
  • 会发现每次都会执行方法逻辑,无论缓存是否存在。

3.@CacheEvict

  • allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。
  • 清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。

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) {returnnull;}

5.@CacheConfig

  • 用于抽取该类下面的共同配置,以下为源码
package org.springframework.cache.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheConfig {String[] cacheNames() default {};String keyGenerator() default "";String cacheManager() default "";String cacheResolver() default "";
}
  • 可以在类上注明,like this

二、以上使用的是Spring自带缓存,可以对cache配置进行修改,改为redis,以下介绍过程

  1. 配置
package com.frame.util.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;import java.time.Duration;/*** @Description:* @date: 2022/5/25 15:21* @author: towards* @since JDK 1.8*//*** 自定义 RedisTemplate*/
@Configuration
public class RedisConfig {@Autowiredprivate LettuceConnectionFactory lettuceConnectionFactory;@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();template.setConnectionFactory(factory);Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL,JsonTypeInfo.As.WRAPPER_ARRAY);jackson2JsonRedisSerializer.setObjectMapper(om);StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();// key 采用 String 的序列化方式template.setKeySerializer(stringRedisSerializer);// hash 的 key 也采用 String 的序列化方式template.setHashKeySerializer(stringRedisSerializer);// value 序列化方式采用 jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash 的 value 序列化方式采用 jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}@Beanpublic RedisCacheManager redisCacheManager(RedisTemplate redisTemplate){RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMillis(30000))//设置缓存过期时间.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));RedisCacheManager build = RedisCacheManager.builder(lettuceConnectionFactory).cacheDefaults(configuration).build();return build;}}
  1. 使用注解
    @Cacheable(cacheNames = "phoneCache",cacheManager = "redisCacheManager",keyGenerator = "myKeyGenerate")
public <T> ResultVo getPhone(Integer id) throws Exception {T value = redisService.getKey(keyGenorate(id));if (ObjectUtils.isNotEmpty(value)){// 如果缓存中有,直接返回log.info("query phone from redis");return ResultVo.success(value);}// 缓存中没有,查询数据不为空时,存入缓存TbPhone tbPhone = tbPhoneDao.queryById(id);if (!ObjectUtils.isEmpty(tbPhone)){log.info("query from mysql ,and save to redis");
//            redisService.setKey(keyGenorate(id), tbPhone);return ResultVo.success(tbPhone);}// 缓存和数据库都没有throw new Exception("query phone in redis and mysql is not exist");}
  1. 查看缓存

@Cacheable使用spring缓存相关推荐

  1. Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入调用 方法 ,第二次不调用的异常

    Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入调用 方法 ,第二次不调用的异常 参考文章: (1)Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入 ...

  2. spring缓存注解@Cacheable和@CacheEvict,设置过期时间和批量模糊删除

    spring缓存注解@Cacheable和@CacheEvict,设置过期时间和批量模糊删除 配置 CacheManager 类 key前缀配置 RedisCache配置 RedisCache 模糊匹 ...

  3. Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

    从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...

  4. Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项

    文章目录 一.概述 二.缓存注解种类 三.优劣势说明 四.如何使用? 五.详细介绍介绍 1)@Cacheable(常用) 1.value/cacheNames 属性 2.key属性 3.keyGene ...

  5. spring缓存_有关Spring缓存性能的更多信息

    spring缓存 这是我们最后一篇关于Spring的缓存抽象的文章的后续文章 . 作为工程师,您可以通过了解所使用的某些工具的内部知识来获得宝贵的经验. 了解工具的行为有助于您在做出设计选择时变得更加 ...

  6. 简单的Spring Memcached – Spring缓存抽象和Memcached

    在任何读取繁重的数据库应用程序中,缓存仍然是最基本的性能增强机制之一. Spring 3.1发行版提供了一个很酷的新功能,称为Cache Abstraction . Spring Cache Abst ...

  7. cacheable 表达式_Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

    从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...

  8. 16课:关于Springboot和@Cacheable注解拉去缓存,@CacheEvict清空缓存的原理

    16课:关于Springboot和@Cacheable注解拉去缓存,@CacheEvict清空缓存的原理 简介 代码展示 1.pox.xml 2.application.properties文件 3. ...

  9. Spring指南之使用Spring缓存数据(Spring Framework官方文档之缓存抽象详解)

    1.请参见官方文档Spring指南之使用 Spring 缓存数据 2.请参见Spring官方文档之缓存抽象 3.参见github代码 文章目录 一.简介 二.你将创造什么(What You Will ...

最新文章

  1. 拖拽的原生和jQuery写法
  2. clcikhouse Code: 1000. DB::Exception: File not found
  3. python集合用法_Python 集合(Set)
  4. 2016年《大数据》杂志调查问卷
  5. 【C语言及程序设计】项目1-24-4:个人所得税计算器if语句版
  6. 《架构探险》第三章 项目核心实现
  7. 对一个存储过程语法的解读
  8. bzoj 1609: [Usaco2008 Feb]Eating Together麻烦的聚餐(DP)
  9. 50余家光伏企业竞标混战:0.52元最低价仍有利润!
  10. 【英雄联盟动画-双城之战】10点首播!6亿召唤师快来
  11. 开通微信小程序直播的条件有哪些?开直播要做什么准备?
  12. 看程序员如何使用Python快速给视频添加字幕
  13. iOS Mach-O文件
  14. 将现有android项目打包成aar包供第三方应用调用
  15. [论文解读]微信看一看实时Look-alike推荐算法
  16. 内容提交的时一个图片,但是前端显示的时<img src=“地址“>而不是图片
  17. 俊哥的HADOOP之路
  18. 简析PPC的Device Tree机制
  19. webApp滚动选择器-实践与应用
  20. STM32F103低功耗测试

热门文章

  1. 与六年测试工程师促膝长谈,他分享的这些让我对软件测试工作有了全新的认知~
  2. oracle11g 建立全文索引
  3. mysql在dos界面修改密码
  4. 微信小程序开发入门(二)image标签及图片样式
  5. 将titles_test表名修改为titles_2017
  6. C# 中 volatile 关键字的解读
  7. 计算机考试函数应用题及答案,2016年全国职称计算机考试EXCEL考前练习题4
  8. PAT_乙级_1009_筱筱
  9. 工业设计公司:从外观设计到软硬件设计
  10. 黑苹果 10G 网卡(intel Aquantia)解决方案及big sur 11.x 下驱动方式