【发布时间】: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<EavAttributeSet> fetchAllAttributes() { return eavAttributeService.fetchAllEavattributesets(); } -
抱歉,我错过了
@CacheResult注释上的显式超时。 -
很好@DanBerindei,有什么解决问题的建议/提示吗??
标签: spring-boot caching infinispan infinispan-9