多模块项目使用枚举配置spring-cache缓存

javalover123
• 阅读 473

一、前言

  1. 近期被刷接口了,考虑增加 本地缓存提高性能,另配置 限流
  2. 使用 spring-cache 注解式缓存,可以提高使用缓存的开发效率
  3. 不同业务,可以定制 自己的缓存策略,是基本需求
  4. 多模块项目,最好在 统一的模块(如 common) 加载缓存配置

二、方案

1. 配置缓存:接口 + 枚举 + Lombok

缓存配置接口:

public interface ICacheConfig {

    Integer getTtl();

}

common模块缓存配置(使用 Lombok 的 FieldNameConstants 自动生成 常量):

@lombok.Getter
@lombok.AllArgsConstructor
@lombok.experimental.FieldNameConstants(onlyExplicitlyIncluded = true)
public enum CommonCacheConfig implements ICacheConfig {

    @FieldNameConstants.Include QUOTE_LEVEL(1000, 2);

    private final Integer ttl;

}

业务模块缓存配置:

@lombok.Getter
@lombok.AllArgsConstructor
@lombok.experimental.FieldNameConstants(onlyExplicitlyIncluded = true)
public enum QuoteServiceCacheConfig implements ICacheConfig {

    @FieldNameConstants.Include HOT_STOCK(1000, 30);

    private final Integer ttl;

}

2. 多模块配置加载:Reflections + SimpleCacheManager

  • 通过 Reflections 库加载多模块配置

  • SimpleCacheManager 组合 各种不同配置的 缓存

    @EnableCaching
    @Configuration
    public class CacheConfig {
      private Logger log = LoggerFactory.getLogger(this.getClass());
      @Bean
      @Primary
      public CacheManager cacheManager() {
          final SimpleCacheManager cacheManager = new SimpleCacheManager();
    
          final String prefix = "package";
        Set<Class<? extends ICacheConfig>> classes = new Reflections(prefix).getSubTypesOf(ICacheConfig.class);
        log.info("cache types|{}|{}", prefix, classes);
        List<Cache> caches = classes.stream().flatMap(clazz -> Arrays.stream(clazz.getEnumConstants())).map(config -> {
            final Caffeine<Object, Object> cache = Caffeine.newBuilder().recordStats();
            Optional.ofNullable(config.getTtl()).ifPresent(t -> cache.expireAfterWrite(t, TimeUnit.SECONDS));
            return new CaffeineCache(((Enum) config).name(), cache.build());
        }).collect(Collectors.toList());
        cacheManager.setCaches(caches);
        return cacheManager;
    }

3. 使用缓存

  • 使用 @Cacheable(cacheNames = CommonCacheConfig.Fields.QUOTE_LEVEL, sync = true) 操作缓存

  • 使用 Lombok 的 FieldNameConstants 自动生成的 常量:

    public enum CommonCacheConfig implements ICacheConfig {
    
      public static final class Fields {
          public static final String QUOTE_LEVEL = "QUOTE_LEVEL";
      }
    

}


## 三、总结
- 通过 接口 + 枚举,业务模块不用改common模块, 新增枚举 就能 方便的配置、使用缓存,符合 开闭原则
- 通过 Lombok 的 FieldNameConstants 自动生成 枚举名称常量,便于代码 导航、重构
- 通过 Reflections 库,common模块自动加载 各模块的缓存配置,SimpleCacheManager 组合 各种不同配置的 缓存(CaffeineCacheManager 不能),降低使用成本,提高可维护性
- sync = true,加锁,只有一个线程去加载数据,其他线程阻塞,防止 缓存击穿
- [alibaba/jetcache](https://github.com/alibaba/jetcache/blob/master/introduce_CN.md):支持TTL和两级缓存、自动刷新和加载保护 等
- [netease-im/camellia](https://github.com/netease-im/camellia/blob/master/docs/cache/cache.md):网易开源,有意思的是  支持基于注解执行mget,mevict等批量操作

本文首先发布于 [https://www.890808.xyz/](https://www.890808.xyz/) ,其他平台需要审核更新慢一些。

![javalover123](https://img.890808.xyz/file/javalover123/2023/04/688b88cfd4ed9f6fcd56828b849ce47c.jpg)
点赞
收藏
评论区
推荐文章
混世魔王 混世魔王
1年前
皕杰报表的缓存问题
设置缓存是提高报表性能的手段之一,皕杰报表在配置文件reportconfig.xml中对缓存进行设置。在系统模式中通过设置开发模式或生产模式来确定是否启用报表缓存。develop在缓存设置中设置缓存方式。1、使用皕杰内置的缓存(即:设置eh"false")
Stella981 Stella981
3年前
Guava的两种本地缓存策略
Guava的两种缓存策略缓存在很多场景下都需要使用,如果电商网站的商品类别的查询,订单查询,用户基本信息的查询等等,针对这种读多写少的业务,都可以考虑使用到缓存。在一般的缓存系统中,除了分布式缓存,还会有多级缓存,在提升一定性能的前提下,可以在一定程度上避免缓存击穿或缓存雪崩,也能降低分布式缓存的负载。Guav
Easter79 Easter79
3年前
SpringCache的事务管理与单元测试
项目背景在某个项目中,使用了SpringCacheredis作为缓存解决方案,jpa作为orm在单元测试时,在执行某步操作时,需要往缓存中放入数据,之后启用断言判断对应的缓存是否存在,结果全部报缓存不存在项目配置springCache@BeanpublicCacheManager
Stella981 Stella981
3年前
Hibernate(四)——缓存策略+lazy
Hibernate作为和数据库数据打交道的框架,自然会设计到操作数据的效率wenti,而对于一些频繁操作的数据,缓存策略就是提高其性能一种重要手段,而Hibernate框架是支持缓存的,而且支持一级和二级两种缓存,合理的使用缓存策略可以大大提高我们的操作数据效率,但是利用不能,可能会造成不必要的麻烦。一,一级缓存(Session缓
Stella981 Stella981
3年前
Mybatis(四)—— Mybatis 缓存
一、Mybatis缓存MyBatis包含一个非常强大的查询缓存特性,使用缓存可以使应用更快地获取数据,避免频繁的数据库交互二、Mybatis缓存分类1.一级缓存:SqlSession的缓存一级缓存默认会启用,想要关闭一级缓存可以在select标签上配置flushCache“true”;
京东云开发者 京东云开发者
1个月前
缓存之美——如何选择合适的本地缓存?
作者:京东保险郭盼1、简介小编最近在使用系统的时候,发现尽管应用已经使用了redis缓存提高查询效率,但是仍然有进一步优化的空间,于是想到了比分布式缓存性能更好的本地缓存,因此对领域内常用的本地缓存进行了一番调研,有早期的Guava缓存、在Guava上进一
javalover123 javalover123
1年前
怎么把Java枚举名称作为注解的属性值
Java注解的属性值,必须为常量。有些场景想把枚举名称设置为注解的属性值(如springcache用枚举配置缓存,使用时需要缓存名称)
京东云开发者 京东云开发者
11个月前
缓存之美——如何选择合适的本地缓存?
1、简介小编最近在使用系统的时候,发现尽管应用已经使用了redis缓存提高查询效率,但是仍然有进一步优化的空间,于是想到了比分布式缓存性能更好的本地缓存,因此对领域内常用的本地缓存进行了一番调研,有早期的Guava缓存、在Guava上进一步传承的Caffi
京东云开发者 京东云开发者
11个月前
基于javaPoet的缓存key优化实践
一.背景在一次系统opsreview中,发现了一些服务配置了@Cacheable注解。@cacheable来源于springcache框架中,作用是使用aop的方式将数据库中的热数据缓存在redis/本地缓存中,代码如下:@Cacheable(value"
小白学大数据 小白学大数据
5个月前
使用Scrapy进行网络爬取时的缓存策略与User-Agent管理
缓存策略的重要性缓存策略在网络爬虫中扮演着至关重要的角色。合理利用缓存可以显著减少对目标网站的请求次数,降低服务器负担,同时提高数据抓取的效率。Scrapy提供了多种缓存机制,包括HTTP缓存和Scrapy内置的缓存系统。HTTP缓存HTTP缓存是基于HT
javalover123
javalover123
Lv1
10年Java经验,多个开源项目贡献者。https://github.com/javalover123
文章
16
粉丝
2
获赞
5