【问题标题】:Infinispan + Spring Boot - Doesn't CacheInfinispan + Spring Boot - 不缓存
【发布时间】:2020-03-16 20:42:09
【问题描述】:

尝试使用自定义注解在 Spring Boot 上实现 infinispan 基础缓存:

@Aspect
@Configuration
@Slf4j
public class CacheAnnotationAspect {
    Logger logger = LoggerFactory.getLogger(CacheAnnotationAspect.class);

    @Autowired
    InfinispanCacheService cacheService;

    @Around("@annotation(com.calsoft.lib.cache.CacheResult)")
    public Object cacheResult(ProceedingJoinPoint joinPoint)throws Throwable{
        logger.info("Cache Operation :: CacheResult annotation advice invoked...");
        CacheResult cacheResult=(CacheResult) getAnnotation(joinPoint,CacheResult.class);
        CacheConfig cacheConfig=CacheConfig.from(cacheResult);
        Object resultFromCache=getFromCache(joinPoint,cacheConfig);
        if(resultFromCache!= null){
            return resultFromCache;
        }
        Object result=joinPoint.proceed(joinPoint.getArgs());
        storeInCache(result,joinPoint,cacheConfig);
        return result;
    }

    private void storeInCache(Object result, ProceedingJoinPoint joinPoint, CacheConfig cacheConfig) {
        if(result==null){
            log.info("Cache op :: null values not cached");
            return;
        }
        CacheService cacheService=getCacheService();
        if(cacheService==null){
            logger.info("Cache op :: CacheGet Failed : No CacheService available for use..");
        }
        DefaultCacheKey defaultCacheKey=getKey(joinPoint,cacheConfig);
        String cacheName=getCacheName(cacheConfig.getCacheName(),joinPoint);
        long lifeSpan=cacheConfig.getLifespan();
        if(lifeSpan== CommonConstant.CACHE_DEFAULT_LIFE){
            cacheService.put(cacheName,defaultCacheKey,result);
        }else{
            cacheService.put(cacheName,defaultCacheKey,result,lifeSpan,cacheConfig.getUnit());
        }
        logger.info("Cache Op :: Result cached :: {} ",cacheConfig);
    }

    private DefaultCacheKey getKey(ProceedingJoinPoint joinPoint, CacheConfig cacheConfig) {
        List<Object> keys=new ArrayList<>();
        Object target=joinPoint.getTarget();
        MethodSignature methodSignature=MethodSignature.class.cast(joinPoint.getSignature());
        Method method=methodSignature.getMethod();
        Annotation[][] parameterAnnotations=method.getParameterAnnotations();
        if(isEmpty(trim(cacheConfig.getKeyPrefix()))){
            keys.add(target.getClass().getName());
            keys.add(method.getName());
        }else{
            keys.add(cacheConfig.getKeyPrefix());
        }
        if(isCacheKeySpecified(parameterAnnotations)){
            keys.addAll(getCacheKeys(joinPoint,parameterAnnotations));
        }else{
            keys.addAll(Arrays.asList(joinPoint.getArgs()));
        }
        return new DefaultCacheKey(keys.toArray());
    }

    private Collection<?> getCacheKeys(ProceedingJoinPoint joinPoint, Annotation[][] parameterAnnotations) {
    Object[] args=joinPoint.getArgs();
    List<Object> result=new ArrayList<>();
    int i=0;
    for(Annotation[] annotations: parameterAnnotations){
        for(Annotation annotation: annotations){
            if(annotation instanceof CacheKey){
                result.add(args[i]);
                break;
            }
        }
        i++;
    }
    return result;
    }

    private boolean isCacheKeySpecified(Annotation[][] parameterAnnotations) {
        for(Annotation[] annotations:parameterAnnotations){
            for(Annotation annotation:annotations){
               if(annotation instanceof CacheKey) {
                return true;
               }
            }
        }
        return false;
    }

    private Object getFromCache(ProceedingJoinPoint joinPoint, CacheConfig cacheConfig) {
        CacheService cacheService = getCacheService();
        if (cacheService == null) {
            logger.info("Cache op :: CacheGet Failed : No CacheService available for use..");
        }
        String cacheName=getCacheName(cacheConfig.getCacheName(),joinPoint);
        DefaultCacheKey defaultCacheKey=getKey(joinPoint,cacheConfig);

        return cacheService.get(cacheName,defaultCacheKey);
    }

    private String getCacheName(String cacheName, ProceedingJoinPoint joinPoint) {
        boolean nameNotDefined=isEmpty(trim(cacheName));
        if(nameNotDefined){
            logger.error("Cache op :: Cache Name not defined");
        }else{
            CacheService cacheService=getCacheService();
            if(!cacheService.cacheExists(cacheName)){
                throw new RuntimeException("Cache with the name "+ cacheName+" does not exists");
            }
        }
        return cacheName;
    }

    private CacheService getCacheService() {
        return cacheService;
    }

    private Annotation getAnnotation(ProceedingJoinPoint joinPoint, Class type) {
        MethodSignature methodSignature=MethodSignature.class.cast(joinPoint.getSignature());
        Method method=methodSignature.getMethod();
        return method.getAnnotation(type);
    }

}

上面的类> 是自定义注解@CacheResult Aspect 实现,它首先会尝试从缓存中检索,如果没有找到将进行实际的dao调用,然后存储在缓存中。

下面是 InfinispanCacheService 的实现,它调用 cachemager 来获取/放置缓存条目。

@Service
public class InfinispanCacheService implements CacheService {

    Logger logger = LoggerFactory.getLogger(InfinispanCacheService.class);
    @Autowired
    private DefaultCacheManagerWrapper cacheManagerWrapper;
    private DefaultCacheManager infiniCacheManager;

    private DefaultCacheManager initializeCacheManager(){
        if(infiniCacheManager==null){
            infiniCacheManager=cacheManagerWrapper.getCacheManager();
        }
        return infiniCacheManager;
    }
    @PostConstruct
    public void start(){
        logger.info("Initializing...InifinispanCacheService ....");
        initializeCacheManager();
        for(String cacheName : infiniCacheManager.getCacheNames()){
            infiniCacheManager.startCache(cacheName);
        }
    }
    @Override
    public Object get(String cacheName, Object key) {
        return getCache(cacheName).get(key);
    }

    @Override
    public void put(String cacheName, Object key, Object value, long lifespan, TimeUnit unit) {
        Cache cache=getCache(cacheName);
        cache.put(key,value,lifespan,unit);
    }

    @Override
    public void put(String cacheName, Object key, Object value) {
        Cache cache=getCache(cacheName);
        cache.put(key,value);
    }

    private Cache<Object,Object> getCache(String cacheName) {
        Cache<Object,Object> cache;
        if(isEmpty(trim(cacheName))){
            cache=infiniCacheManager.getCache();
        }else{
            cache=infiniCacheManager.getCache(cacheName,false);
        }
        return cache;
    }

    @Override
    public boolean cacheExists(String cacheName) {
        return infiniCacheManager.cacheExists(cacheName);
    }
}

>>>>

@Component
public class DefaultCacheManagerWrapper {

    Logger logger = LoggerFactory.getLogger(DefaultCacheManagerWrapper.class);
//    @Value("${classpath:spring.cache.infinispan.config}")
    private String fileName="file:\\calsoft\\devlabs\\ecom2\\ecom-svc-admin\\src\\main\\resources\\infinispan.xml";
    private DefaultCacheManager infiniCacheManager;

    @PostConstruct
    public void start(){
        logger.info(" Received File Name :: {} ",fileName);
        try{
            URL fileUrl=new URL(fileName);
            URLConnection urlConnection=fileUrl.openConnection();
            InputStream inputStream=urlConnection.getInputStream();
            infiniCacheManager=new DefaultCacheManager(inputStream);
            infiniCacheManager.start();
            logger.info("Cache Manager Initialized....");
        }catch(MalformedURLException mue){
            logger.error("Error creating file url ",mue.getMessage());
        } catch (IOException e) {
            logger.error("Error creating file url ",e.getMessage());
        }
    }
    public void stop() { infiniCacheManager.stop();}
    public DefaultCacheManager getCacheManager(){
        return infiniCacheManager;
    }
}

>

   <?xml version="1.0" encoding="UTF-8"?>
<infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:scehmaLocation="
            urn:infinispan:config:7.2
            http://www.infinispan.org/schemas/infinispan-config-7.2.xsd"
            xmlns="urn:infinispan:config:7.2">
    <cache-container default-cache="attributeset-cache">
        <!-- template configurations -->
        <local-cache-configuration name="local-template">
            <expiration interval="10000" lifespan="50000" max-idle="50000"/>
        </local-cache-configuration>

        <!-- cache definitions -->
        <local-cache name="attributeset-cache" configuration="local-template"/>
    </cache-container>
</infinispan>

控制器级别的注释:

@CacheResult(cacheName= CommonConstant.ATTRIBUTE_SET_CACHE,lifespan=10,unit = TimeUnit.MINUTES)
    @GetMapping("/eavattributeset")
    public List<EavAttributeSet> fetchAllAttributes() {
            return eavAttributeService.fetchAllEavattributesets();
    }

>

@Service
public class EavAttributeService {

    Logger logger = LoggerFactory.getLogger(EavAttributeService.class);
    @Autowired
    private EavAttributeJpaRepository eavAttributeJpaRepository;

    @Autowired
    EavAttributeSetJpaRepository eavAttributeSetJpaRepository;  

    public List<EavAttributeSet> fetchAllEavattributesets() {

        return eavAttributeSetJpaRepository.findAll();

    }
}

>

@Data
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
public class CacheConfig {
    private String cacheName;
    private long lifespan;
    private TimeUnit unit;
    private String keyPrefix;

    public static CacheConfig from(CacheResult cacheResult) {
        return new CacheConfig(cacheResult.cacheName(), cacheResult.lifespan(), cacheResult.unit(), cacheResult.keyPrefix());
    }

}

问题: 数据没有得到缓存,无论在哪里使用 @CacheResult 注释,都会调用 CacheAnnotationAspect 并且数据检查也发生在缓存中,但是当它尝试将数据存储在缓存中时不缓存,以后每次调用此方法都不会返回任何数据。

【问题讨论】:

  • 您确定这些值没有被缓存,并且它们不会在配置的 10 毫秒后过期吗?
  • @DanBerindei 感谢您的回复,我什至将它增加到 60000 毫秒,但它似乎仍然没有缓存,因为每个方法命中都会调用 dao。
  • 我也有寿命作为属性之一@CacheResult(cacheName= CommonConstant.ATTRIBUTE_SET_CACHE,lifespan=10,unit = TimeUnit.MINUTES) @GetMapping("/eavattributeset") public List&lt;EavAttributeSet&gt; fetchAllAttributes() { return eavAttributeService.fetchAllEavattributesets(); }
  • 抱歉,我错过了 @CacheResult 注释上的显式超时。
  • 很好@DanBerindei,有什么解决问题的建议/提示吗??

标签: spring-boot caching infinispan infinispan-9


【解决方案1】:

当我在 infinispan.xml 上尝试以下配置时,它工作正常。

&lt;expiration lifespan="50000"/&gt;

你可以试试上面的配置,看看它是否使用缓存的数据。

我猜这可能是最大空闲超时(10 毫秒)的问题。

【讨论】:

  • 我尝试延长使用寿命(请参阅上面的更新 infinispan.xml),但没有解决问题。它仍然没有缓存。
  • 实际上它也适用于您更新的配置。..您可以分享 CacheConfig 代码
  • 在上面的代码 sn-p 中添加了 >,这对你在 spring boot + Embedded Tomcat/Standalone Tomcat 中是否有效
  • 是的,使用 springboot + 嵌入式 tomcat。我已将我的样本上传到github.com/samuel-coder/infinispanaspectsample。请试一试。
  • 抱歉耽搁了,我在尝试运行应用程序时遇到错误。抱歉耽搁了,我在尝试运行示例时遇到错误……BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Advice must be declared inside an aspect type: Offending method 'public java.lang.Object com.samples.CacheAnnotationAspect.cacheResult(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable' in class com.samples.CacheAnnotationAspect] at
猜你喜欢
  • 2017-03-26
  • 2013-09-05
  • 2021-05-09
  • 1970-01-01
  • 1970-01-01
  • 2016-10-13
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多