• 缓存-Spring Cache 缓存抽象


    缓存-Spring Cache 缓存抽象

           Spring从版本3.1开始提供非侵入的将Cache集成到Spring应用的方式。Spring Cache提供Cache的统一抽象,支持集成各种不同的缓存解决方案。从4.1版本开始,提供了注解和更多的定制参数。

           Spring Cache 抽象提供了对Java方法的缓存,使用Spring Cache缓存,当方法调用使用相同的参数,调用结果被缓存下来,当方法被再次调用时将直接返回参数结果。

    关键类和接口

    Cache

    org.springframework.cache.Cache 提供Spring框架中使用的Cache的统一抽象功能, 具体的实现类使用实际的缓存解决方案。

    • NoOpCache: 空缓存,没有实际的缓存实现
    • EhCacheCache: 使用EhCache缓存方案。
    • CaffeineCache: 使用Java CaffeineCache。Caffeine提出了一种更高效的近似LFU准入策略的缓存结构TinyLFU及其变种W-TinyLFU,借鉴Guava Cache的设计经验,是一款功能强大,性能更优本地缓存。
    • JCacheCache: Javax Cache 标准接口,类似于Spring Cache的 JavaJ JSR缓存规范。
    • ConcurrentMapCache: 使用ConccrentMap的缓存实现。
    • TransactionAwareCacheDecorator: 识别Spring 事务的缓存实现装饰模式,只要当事务提交时才触发缓存的更新。

    CacheManager

    org.springframework.cache.CacheManager:Spring cache 管理API。不同的CacheManager实现提供对相应Cache实现缓存的管理,通过管理API Cache getCache(String name);方法对外提供。

    CacheResolver

    org.springframework.cache.interceptor.CacheResolver 方法调用拦截使用来获取Cache实现的Resolver,通常使用相应的CacheManager实现类来获取Cache。

    KeyGenerator

    org.springframework.cache.interceptor. KeyGenerator: 缓存中Key的生成实现。默认的key生成器:org.springframework.cache.interceptor.SimpleKeyGenerator 类

    1.    方法没有参数则使用SimpleKey.EMPTY

    2.    方法只有一个参数:key=唯一参数

    3.    方法有多个参数:SimpleKey(params)

    可以通过实现org.springframework.cache.interceptor.KeyGenerator接口定制key生成器。

    使用Spring Cache

    启用Spring Cache

    @Configuration

    @EnableCaching

    注解使用

    @Cacheable: 作用于方法之上,配置方法缓存

    @Cacheable("cacheName"): 指定用于缓存结果的缓存名称,当指定多个名称时,方法调用将在多个缓存中查找相同参数的方法调用,命中即返回。

    Cache 的key

           指定KeyGenerator:

    @Cacheable(cacheNames="XXX", keyGenerator="myKeyGenerator")。

           通过SpEL指定key

           @Cacheable(cacheNames="books", key="#isbn")

    public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

    @CachePut: @CachePut指定的方法不影响方法的执行,方法执行结果将用于更新缓存。@CachePut支持同@Cacheable一样的配置。

    示例:

    @CachePut(cacheNames="book", key="#isbn")

    public Book updateBook(ISBN isbn, BookDescriptor descriptor)

    @CacheEvict: 触发缓存清理陈旧或无用的数据。可以配置指定数据的清理或Cache范围的清理。

    示例:

    @CacheEvict(cacheNames="books", allEntries=true)

    public void loadBooks(InputStream batch)

    @Caching: 在一个方法上指定触发缓存的多个操作。

    示例:

    @Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })

    public Book importBooks(String deposit, Date date)

    @CacheConfig: 以上的注解都是方法级别的注解,@CacheConfig提供类级别的公共配置,该类下的方法级别配置如无指定则使用类级别上的@CacheConfig。

    实现方式

    Spring AOP

    使用 Spring AOP切面实现Cache相关方法的拦截获取缓存和Cache请求的处理

    1. 配置切面: 所有所有类和所有方法都进行拦截

    org.springframework.cache.interceptor.CacheProxyFactoryBean

    相关代码:

    private Pointcut pointcut = Pointcut.TRUE;

            

    protected Object createMainInterceptor() {

             this.cacheInterceptor.afterPropertiesSet();

             return new DefaultPointcutAdvisor(this.pointcut, this.cacheInterceptor);

    }

    1. org.springframework.cache.interceptor.CacheInterceptor 实现

    org.springframework.cache.interceptor.MethodInterceptor接口,

    CacheAspectSupport.execute方法是Spring Cache核心处理流程,下面是主要流程的部分代码解析:

    // 处理CacheEvict请求

    processCacheEvicts(contexts.get(CacheEvictOperation.class), true,

             CacheOperationExpressionEvaluator.NO_RESULT);

    // 从缓存中查询是否存在缓存

    Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

    // 如未命中,生成CachePut请求:缓存条件满足

    List cachePutRequests = new ArrayList<>();

    if (cacheHit == null) {

             collectPutRequests(contexts.get(CacheableOperation.class),

                              CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);

    }

    Object cacheValue;

    Object returnValue;

    if (cacheHit != null && !hasCachePut(contexts)) {

             //缓存命中,并且没有Put需求,返回缓存值

             cacheValue = cacheHit.get();

             returnValue = wrapCacheValue(method, cacheValue);

    }

    else {

             //未命中,调用对象,获取可缓存值

             returnValue = invokeOperation(invoker);

             cacheValue = unwrapReturnValue(returnValue);

    }

    //检查是否存在CachePut请求

    collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

    // 缓存更新

    for (CachePutRequest cachePutRequest : cachePutRequests) {

             cachePutRequest.apply(cacheValue);

    }

    // 处理缓存Evicts请求

    rocessCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);      

    return returnValue;

    }

  • 相关阅读:
    和对手‘打’成一片
    MySQL 主从同步(读写分离)
    flink1.15 异步维表Join 用于外部数据访问的异步 I/O scala版本
    Leetcode 386. 字典序排数
    从内核角度看网络包发送流程
    jmeter 性能测试工具的使用(Web性能测试)
    使用 Flutter 与 Firebase 制作 I/O 弹球游戏
    机器人算法—ROS TF坐标变换
    谷粒商城14——订单支付(AliPay)
    SpringBoot 概念、优点以及网页版创建
  • 原文地址:https://blog.csdn.net/dreamsofa/article/details/134274223