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