程序员子龙(Java面试 + Java学习) 程序员子龙(Java面试 + Java学习)
首页
学习指南
工具
开源项目
技术书籍

程序员子龙

Java 开发从业者
首页
学习指南
工具
开源项目
技术书籍
  • 基础

  • JVM

  • Spring

    • 动态代理-CGLIB
    • Hibernate Validator 参数校验优雅实战
    • Jackson序列化json时null转成0或空串
    • 别自己瞎写工具类了!SpringBoot中自带工具类,开发效率增加一倍
    • Spring @Autowired Map
    • SpringBoot 缓存之 @Cacheable 详细介绍与失效时间TTL
      • Spring Security 入门
      • Spring Security原理
      • Spring项目整合MybatisPlus出现org.mybatis.logging.LoggerFactory Not Found 异常
      • Spring在代码中获取bean
      • 别再乱写了,Controller 层代码这样写才足够规范!
      • 非静态变量给静态变量赋值
      • 过滤器与拦截器区别、使用场景
      • 接口重试机制 Spring-Retry
      • 利用cglib动态创建对象或在原对象新增属性
      • 聊聊spring事务失效的场景
      • Spring Event 事件解耦
      • 最全的Spring依赖注入方式
      • Spring初始化之ApplicationRunner、InitializingBean、@PostConstruct 使用详解
      • 为啥不建议用 BeanUtils.copyProperties 拷贝数据
    • 并发编程

    • Mybatis

    • 网络编程

    • 数据库

    • 缓存

    • 设计模式

    • 分布式

    • 高并发

    • SpringBoot

    • SpringCloudAlibaba

    • Nginx

    • 面试

    • 生产问题

    • 系统设计

    • 消息中间件

    • Java
    • Spring
    程序员子龙
    2024-01-29
    目录

    SpringBoot 缓存之 @Cacheable 详细介绍与失效时间TTL

    Spring 从 3.1 开始就引入了对 Cache 的支持。定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术。并支持使用 JCache(JSR-107)注解简化我们的开发。

    # @Cacheable 注解使用

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

    @SpringBootApplication
    @EnableCaching
    public class SpringbootRedisApplication {
    
        public static void main(String[] args) {
    
            SpringApplication.run(SpringbootRedisApplication.class,args);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    2、标注缓存注解即可

    
        @Cacheable(value = "city",key = "#city.id")
        public City getCity(City city){
    
            //模拟查询
            return new City("北京","首都");
        }
    //缓存key:city::1
    
    1
    2
    3
    4
    5
    6
    7
    8

    @Cacheable这个注解常用的几个属性:

    • cacheNames/value :用来指定缓存组件的名字
    • key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)

    • keyGenerator :key 的生成器。 key 和 keyGenerator 二选一使用.

      首先自定义keyGenerator

          @Bean("myKeyGenerator")
          public KeyGenerator keyGenerator() {
      
              return new KeyGenerator() {
                  @Override
                  public Object generate(Object target, Method method, Object... params) {
                      StringBuilder sb = new StringBuilder();
                      sb.append(target.getClass().getName());
                      sb.append(method.getName());
                      for (Object obj : params) {
                          sb.append(obj.toString());
                      }
                      return sb.toString();
                  }
              };
          }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
         @Cacheable(value = "city",keyGenerator = "myKeyGenerator")
          public City getCity(City city){
      
              //模拟查询
              return new City("北京","首都");
          }
      
      //缓存key:city::com.demo.service.CityServicegetCityCity{id=1, provinceId=null, cityName='null', description='null'}
      
      1
      2
      3
      4
      5
      6
      7
      8
    • cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。

    • condition :可以用来指定符合条件的情况下才缓存

    • unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)

    • sync :是否使用异步模式。默认是方法执行完,以同步的方式将方法返回的结果存在缓存中。j

    # 设置缓存过期时间

    Spring @Cacheable是并不支持Expire失效时间的设定的。

    若想在缓存注解上指定失效时间,必须具备如下两个基本条件:

    • 缓存实现产品支持Expire失效时间(Ehcache、Redis等几乎所有第三方实现都支持)
    • xxxCacheManager管理的xxxCache必须扩展了Expire的实现

    因为缓存的k-v键值对具有自动失效的特性实在太重要和太实用了,所以虽然org.springframework.cache.Cache它没有实现Expire,但第三方产品对Spring缓存标准实现的时候,大都实现了这个重要的失效策略,比如典型例子:RedisCache。

    本文介绍自定义cacheNames方式,实现redis缓存过期时间

    # 自定义RedisCacheManager

    public class CustomRedisCacheManager extends RedisCacheManager {
    
        public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
            super(cacheWriter, defaultCacheConfiguration);
        }
    
       /**
        * 针对@Cacheable设置缓存过期时间
        * @param name
        * @param cacheConfig
        * @return
        */
        @Override
        protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
            String[] array = StringUtils.delimitedListToStringArray(name, "#");
            name = array[0];
          // 解析TTL
            if (array.length > 1) {
                long ttl = Long.parseLong(array[1]);
                cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl)); // 注意单位我此处用的是秒,而非毫秒
            }
            return super.createRedisCache(name, cacheConfig);
        }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    # 配置CacheConfig

    @EnableCaching // 使用了CacheManager,别忘了开启它  否则无效
    @Configuration
    public class CacheConfig extends CachingConfigurerSupport {
    
        @Bean
        public CacheManager cacheManager() {
            RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                    .entryTtl(Duration.ofDays(1))
                    .computePrefixWith(cacheName -> "caching:" + cacheName);
    
            MyRedisCacheManager redisCacheManager = new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory()), defaultCacheConfig);
            return redisCacheManager;
        }
    
        @Bean
        public RedisConnectionFactory redisConnectionFactory() {
            RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
            configuration.setHostName("xxxx");
            configuration.setPort(6379);
            configuration.setDatabase(0);
            LettuceConnectionFactory factory = new LettuceConnectionFactory(configuration);
            return factory;
        }
    
        @Bean
        public RedisTemplate<String, String> stringRedisTemplate() {
            RedisTemplate<String, String> redisTemplate = new StringRedisTemplate();
            redisTemplate.setConnectionFactory(redisConnectionFactory());
            return redisTemplate;
        }
    
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33

    # 使用@Cacheable

    @Service
    public class CacheDemoServiceImpl implements CacheDemoService {
    
        // #后面是缓存过期时间
        @Cacheable(cacheNames = {"testCache#3600"}, key = "#id")
        @Override
        public Object getFromDB(Integer id) {
            return "hello cache...";
        }
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    上次更新: 2024/01/30, 15:08:57
    Spring @Autowired Map
    Spring Security 入门

    ← Spring @Autowired Map Spring Security 入门→

    最近更新
    01
    一个注解,优雅的实现接口幂等性
    11-17
    02
    MySQL事务(超详细!!!)
    10-14
    03
    阿里二面:Kafka中如何保证消息的顺序性?这周被问到两次了
    10-09
    更多文章>
    Theme by Vdoing | Copyright © 2024-2024

        辽ICP备2023001503号-2

    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式