0

尝试使用自定义注释在 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);
    }

}

上面的类 << CacheAnnotationAspect >> 是自定义注释@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);
    }
}

<<<<<< 下面的 DefaultCacheManager 是在启动期间通过加载 infispan.xml 配置来初始化 DefaultCacheManager >>>>>

@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;
    }
}

<<<< Infinispan.xml 配置 >>

   <?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();
    }

<< EavAttributeService >>

@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 并且数据检查也在缓存中发生,但是当它尝试将数据存储在缓存中时,它不会缓存并且每次后续调用此方法不返回任何数据。

4

1 回答 1

0

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

<expiration lifespan="50000"/>

您可以尝试使用上述配置并查看它是否使用缓存的数据。

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

于 2019-11-23T06:43:40.737 回答