码迷,mamicode.com
首页 > 编程语言 > 详细

Spring AOP+自定义注解实现缓存

时间:2015-04-07 15:47:35      阅读:263      评论:0      收藏:0      [点我收藏+]

标签:缓存   spring   annotation   aop   caching   

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)代码如下:

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 CacheOperationContext(Method method, Object[] args, Object target, Class<?> targetClass) {
            this.method = method;
            this.args = extractArgs(method, args);
            this.target = target;
            this.targetClass = targetClass;
            this.methodCacheKey = new MethodCacheKey(method, targetClass);
        }

        public Object getTarget() {
            return this.target;
        }

        public Method getMethod() {
            return method;
        }

        public Object[] getArgs() {
            return this.args;
        }

        private Object[] extractArgs(Method method, Object[] args) {
            if (!method.isVarArgs()) {
                return args;
            }
            Object[] varArgs = ObjectUtils.toObjectArray(args[args.length - 1]);
            Object[] combinedArgs = new Object[args.length - 1 + varArgs.length];
            System.arraycopy(args, 0, combinedArgs, 0, args.length - 1);
            System.arraycopy(varArgs, 0, combinedArgs, args.length - 1, varArgs.length);
            return combinedArgs;
        }

        /**
         * Compute the key for the given caching operation.
         * 
         * @return the generated key, or {@code null} if none can be generated
         */
        public Object generateKey(Cacheable cacheable, Object result) {
            if (StringUtils.hasText(cacheable.key())) {
                EvaluationContext evaluationContext = createEvaluationContext(result);
                return evaluator.key(cacheable.key(), this.methodCacheKey, evaluationContext);
            }
            return keyGenerator.generate(this.target, this.method, this.args);
        }

        private EvaluationContext createEvaluationContext(Object result) {
            return evaluator.createEvaluationContext(Arrays.asList(new Cache[] { cache }), this.method, this.args, this.target, this.targetClass, result);
        }

    }

    /**
     * @param keyGenerator the keyGenerator to set
     */
    public void setKeyGenerator(KeyGenerator keyGenerator) {
        this.keyGenerator = keyGenerator;
    }

    /**
     * @param cache the cache to set
     */
    public void setCache(Cache cache) {
        this.cache = cache;
    }

}

使用自定义注解进行缓存的类的配置:

<bean id="trackingListService" class="cn.vobile.service.trackinglist.TrackingListServiceImpl">
	<property name="trackingListDao" ref="trackingListDao"></property>
</bean>

TrackingListServiceImpl类里面进行缓存的方法:

@Cacheable(key = "'getTrackingListForCompany_'+#companyId+'_'+#orderNumber+'_'+#isContainSubList", timeout = 5, serialize = true)
public List<TrackingList> getTrackingListForCompany(String companyId, int orderNumber, boolean isContainSubList) {
	return trackingListDao.getTrackingListForCompany(companyId, orderNumber, isContainSubList );
}

注:这里面注解里的参数是根据每次调用的时候动态传入的,语法详见:Spring Expression Language (SpEL)

Spring AOP+自定义注解实现缓存

标签:缓存   spring   annotation   aop   caching   

原文地址:http://blog.csdn.net/thjnemo/article/details/44919463

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!