Spring AOP配置:
<aop:config>
<aop:aspect ref="cacheAdvice">
<aop:pointcut id="cachePointcut" expression="execution(* cn.vobile.service..*.*(..)) and @annotation(cacheable)"/>
<aop:around method="cacheData" pointcut-ref="cachePointcut"/>
</aop:aspect>
</aop:config>
<bean id="cacheAdvice" class="cn.vobile.common.cache.aop.CacheAdvice">
<property name="cache" ref="localCache"/>
</bean>
自定义注解Cacheable代码如下:
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {
/**
* The cache key.
*
* @return
*/
String key() default "";
/**
* The cache timeout, unit for minute.
*
* @return
*/
int timeout() default 30;
/**
* Whether serialize the cache object.
*
* @return
*/
boolean serialize() default false;
}
切面处理类(CacheAdvice)及其父类(CacheAdviceSupport)和辅助类(ExpressionEvaluator、CacheExpressionRootObject、CacheEvaluationContext、KeyGenerator、MethodCacheKey、SimpleKey、SimpleKeyGenerator、VariableNotAvailableException)代码如下:
public class CacheAdvice extends CacheAdviceSupport {
public Object cacheData(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method targetMethod = AopUtils.getMostSpecificMethod(methodSignature.getMethod(), joinPoint.getTarget().getClass());
CacheOperationContext context = getOperationContext(targetMethod, joinPoint.getArgs(), joinPoint.getTarget(), joinPoint.getTarget().getClass());
Object key = generateKey(cacheable, context);
Object cacheObject = getCacheObject(cacheable, key);
if (null != cacheObject) {
return cacheObject;
}
Object result = joinPoint.proceed();
if (null != result) {
cacheObject(cacheable, key, result);
}
return result;
}
private Object getCacheObject(Cacheable cacheable, Object key) {
Object cacheObject = cache.get(key);
if (cacheable.serialize()) {
cacheObject = SerializationUtils.deserialize((byte[]) cacheObject);
}
return cacheObject;
}
private void cacheObject(Cacheable cacheable, Object key, Object value) {
if (cacheable.serialize()) {
value = SerializationUtils.serialize(value);
}
cache.put(key, value, cacheable.timeout());
}
}
public abstract class CacheAdviceSupport {
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
private KeyGenerator keyGenerator = new SimpleKeyGenerator();
protected Cache cache;
/**
* Compute the key for the given caching operation.
*
* @return the generated key, or {@code null} if none can be generated
*/
protected Object generateKey(Cacheable cacheable, CacheOperationContext context) {
return context.generateKey(cacheable, ExpressionEvaluator.NO_RESULT);
}
protected CacheOperationContext getOperationContext(Method method, Object[] args, Object target, Class<?> targetClass) {
return new CacheOperationContext(method, args, target, targetClass);
}
protected class CacheOperationContext {
private final Method method;
private final Object[] args;
private final Object target;
private final Class<?> targetClass;
private final MethodCacheKey methodCacheKey;
public CacheOperation