如何在@CacheEvict中调用侦听器或侦听器



我需要在调用@CacheEvict时调用某些功能。有没有办法调用要在春季@CacheEvict中调用的侦听器或拦截器?

通常,这是非常特定于"缓存提供程序"的,因为没有 2 个缓存提供程序具有相同的功能。

例如,我主要使用内存数据网格(IMDG)技术,如Pivotal GemFire和OSS版本Apache Geode。 两者都可以用作Spring 缓存抽象中的"缓存提供程序"。 使用 GemFire/Geode,您可以在支持 SpringCache接口的 GemFire/GeodeRegion(本质上是一个java.util.Map)上注册o.a.g.cache.CacheListener回调,并在Spring的缓存基础架构中用作后备存储"适配器"。 正如您在SD GemFire/Geode提供程序实现中看到的那样,"逐出"触发了GemFire/GeodeRegion.remove(key)。 随后可以在Region's注册的 CacheListener.afterDestroy(:EntryEvent) 回调方法中捕获和处理此逐出。

但是,这只是处理应用程序中逐出通知的一种方法。

当然,正如@Borino指出的那样,您可以利用Spring 的AOP 支持来"拦截"缓存逐出操作。 此方法的优点是它更通用,并且可以在不同的缓存提供程序之间重用。

虽然,我想说你不应该像@Borino指示的那样,基于底层的"缓存提供程序"开发AOP Pointcut表达式,即......

execution(* org.springframework.cache.concurrent.ConcurrentMapCache.evic‌​t(..))

此表达式将您的 AOP 方面绑定到ConcurrentMapCache"提供程序",这是 Spring缓存抽象(和Spring 引导)中的默认值。

当您在应用程序中使用 Ehcache、Hazelcast、Redis、GemFire/Geode 或这些"提供程序"的多种组合时会发生什么?

相反,您可以稍微调整 AOP 切入点表达式...

execution(* org.springframework.cache.Cache.evic‌​t(..))

看这里。 这是安全的,因为所有"缓存提供程序"都必须提供 2 件事:CacheManager实现和应用程序中指定的每个缓存的Cache实现。 同样,Cache接口是后备存储的"适配器"。 同样,请参阅文档以获取更多详细信息。

这两种方法都有权衡。 特定于提供程序的解决方案通常为您提供更多控制功能,但使用 AOP 方法更可重用。做适合您的UC的事情。

希望这有帮助。

干杯! -John

John 的答案是正确的,但重要的是要知道 Cache 类不是 Spring 管理的 bean,而是 CacheManager。

出于这个原因,你必须引入额外的AspectJ依赖项,并进行某种编译或编译后编织来定位Cache.evict方法。

我尝试将缓存管理器注入一个方面,并在需要缓存逐出的方法上设置我的点切入,如下所示:

package com.example.aspectdemo.aop;

import com.example.aspectdemo.domain.Customer;
import com.example.aspectdemo.service.CustomerService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class CacheEvictHandler {
public static Logger logger = LoggerFactory.getLogger(CacheEvictHandler.class);
private final CacheManager cacheManager;
private final CustomerService customerService;
public CacheEvictHandler(CacheManager cacheManager, CustomerService customerService) {
this.cacheManager = cacheManager;
this.customerService = customerService;
}
@Pointcut(value = "execution(* com.example.aspectdemo.service.impl.CustomerServiceImpl.save(..))")
public void loggingPointCut() {
}
@AfterReturning(value = "loggingPointCut()", returning = "customer")
public void LoggAfterEviction(JoinPoint joinPoint, Customer customer) throws Throwable {
cacheManager.getCache("customer-cache").clear();// remove cache
logger.info("*** saved customer id : {}", customer.getId());// do what you like here, i added some logs
logger.info("*** after eviction : {}", customerService.findAll());
logger.info("*** cache evicted ***");
}
}

这是我保存的地方:

@Transactional
@Override
public Customer save(Customer customer) {
log.debug("Request to save Customer : {}", customer);
return customerRepository.save(customer);
}

相关内容