com.joken.base.spring.aop.CacheableAop.java Source code

Java tutorial

Introduction

Here is the source code for com.joken.base.spring.aop.CacheableAop.java

Source

/*
 * @(#)RedisCacheableAop.java   2015-9-29 ?4:12:52
 *
 * Copyright 2015 www.ifood517.com. All rights reserved.
 * www.ifood517.com PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.joken.base.spring.aop;

import java.lang.annotation.Annotation;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import com.joken.common.cache.CacheHandleMode;
import com.joken.common.cache.CacheKey;
import com.joken.common.cache.Cacheable;
import com.joken.common.cache.ExpireKey;
import com.joken.common.cache.RedisTemplate;
import com.joken.common.logger.Logger;
import com.joken.common.logger.LoggerFactory;
import com.joken.common.model.ResponseModel;
import com.joken.common.properties.MsgProperties;
import com.joken.common.properties.SystemGlobal;
import com.joken.common.utils.JSONUtils;
import com.joken.common.utils.StringUtils;

/**
 * ?
 * 
 * @version V1.0.0, 2015-9-29
 * @author 
 * @since V1.0.0
 */
@Aspect
@Component
public class CacheableAop {
    /**
     * ?
     */
    private static Logger logger = LoggerFactory.getLogger("CacheableAop");

    /**
     * ?
     */
    @Autowired(required = false)
    private RedisTemplate redisTemplate;

    /**
     * 
     */
    private static ThreadLocal<Integer> THREAD_CACHE_EXPIRE = new ThreadLocal<Integer>();

    /**
     * AOP?
     * 
     * @param pjp
     *            ?
     * @param cache
     *            
     * @return ?
     * @throws Throwable
     * @date 2015-10-10 ?8:29:11
     */
    @Around("@annotation(cache)")
    public Object cached(final ProceedingJoinPoint pjp, Cacheable cache) throws Throwable {
        THREAD_CACHE_EXPIRE.remove();
        if (redisTemplate == null) {
            return pjp.proceed();
        }

        // ???
        String key = getCacheKey(pjp, cache);
        // ????
        if (StringUtils.isEmpty(key)) {
            return pjp.proceed();
        }
        logger.info("????" + key);

        // ?
        if (cache.handleMode() == CacheHandleMode.delete) {
            this.deleteCaceh(key, cache);
            return pjp.proceed();
        }

        MethodSignature method = (MethodSignature) pjp.getSignature();
        Class<?> clazz = method.getReturnType();

        Object value;
        if (!(cache.handleMode() == CacheHandleMode.append)) {
            // ??
            value = this.getCache(key, cache);
            if (value != null) {
                return this.castValue(clazz, value);
            }
        }

        // ,??
        value = pjp.proceed();

        // ??
        if (value != null && cache.handleMode() != CacheHandleMode.nil) {
            // 
            Object cacheValue = value;
            if (value instanceof ResponseModel) {
                cacheValue = ((ResponseModel) value).getData();
            }

            // ??
            if (cacheValue != null) {
                logger.info("??" + key);
                this.setCache(key, cacheValue, cache);
            }
        }

        return value;
    }

    /**
     * ?key
     * 
     * @param pjp
     *            
     * @param cache
     *            
     * @return 
     */
    private String getCacheKey(ProceedingJoinPoint pjp, Cacheable cache) {
        Annotation[][] pas = ((MethodSignature) pjp.getSignature()).getMethod().getParameterAnnotations();
        StringBuilder buf = new StringBuilder();
        Object[] args = pjp.getArgs();
        Object objVal;
        String val;
        BigDecimal expire;
        List<Object> params = new ArrayList<Object>();
        for (int i = 0; i < pas.length; i++) {
            objVal = args[i];
            if (objVal == null) {
                continue;
            }
            val = objVal.toString();
            val = val.replaceAll(",", "-");
            for (Annotation an : pas[i]) {
                if (an instanceof CacheKey) {
                    if (buf.length() > 0) {
                        buf.append(":");
                    }
                    buf.append(val);
                    params.add(val);
                    break;
                } else if (an instanceof ExpireKey) {// ?
                    try {
                        expire = new BigDecimal(val);
                        THREAD_CACHE_EXPIRE.set(expire.intValue());
                    } catch (Exception e) {
                    }
                }
            }
        }

        if (StringUtils.isEmpty(cache.keyName())) {
            return buf.toString();
        }

        if (cache.keyArray()) {
            return StringUtils.format(SystemGlobal.get(cache.keyName()), params.toArray(new Object[0]));
        }
        return StringUtils.format(SystemGlobal.get(cache.keyName()), buf.toString());

    }

    /**
     * ??
     * 
     * @param key
     *            ????
     * @param cache
     *            ?
     * @return ?
     * @author 
     * @date 2015-10-16 ?8:25:33
     */
    private Object getCache(String key, Cacheable cache) {
        Object value = null;
        if (!redisTemplate.isExist(key)) {
            return value;
        }
        switch (cache.cacheMode()) {
        case LIST:
            value = getCollectionJSON(redisTemplate.lrange(key), cache);
            break;
        case SET:
            value = getCollectionJSON(redisTemplate.sinter(key), cache);
            break;
        case MAP:
            Map<String, String> m = redisTemplate.getMap(key);
            if (m != null && m.size() > 0) {
                value = JSONUtils.parseObject(redisTemplate.getMap(key));
            }
            break;
        case JSON:
            value = JSONUtils.parseObject(redisTemplate.getValue(key));
            break;
        case JSONARRAY:
            value = JSONUtils.parseArray(redisTemplate.getValue(key));
            break;
        default:
            value = redisTemplate.getValue(key);
            break;
        }
        return value;
    }

    /**
     * 
     * 
     * @param key
     *            ??
     * @param value
     *            
     * @param cache
     *            ?
     * @author 
     * @date 2015-10-16 ?8:49:17
     */
    private void setCache(String key, Object value, Cacheable cache) {
        // ??
        int expire = SystemGlobal.getInteger(cache.keyName() + ".expire");
        // ??
        if (expire < 1) {
            expire = cache.expire();
        }
        if (THREAD_CACHE_EXPIRE.get() != null && THREAD_CACHE_EXPIRE.get() > 0) {
            expire = THREAD_CACHE_EXPIRE.get();
        }
        String tmp = null;
        switch (cache.cacheMode()) {
        case LIST:
            List<String> list = this.getCollectionString(value);
            redisTemplate.lpush(key, expire, list.toArray(new String[0]));
            return;
        case SET:
            List<String> vals = this.getCollectionString(value);
            redisTemplate.sadd(key, expire, vals.toArray(new String[0]));
            return;
        case MAP:
            redisTemplate.setObjectMap(key, expire, JSONUtils.parse(JSONUtils.toJSONString(value)));
            return;
        case JSON:
            tmp = JSONUtils.toJSONString(value);
            break;
        case JSONARRAY:
            tmp = JSONUtils.toJSONArray(JSONUtils.toJSONString(value)).toJSONString();
            break;
        default:
            tmp = value.toString();
            break;
        }
        logger.info("?" + key + "," + expire);
        redisTemplate.setValue(key, tmp, expire);
    }

    /**
     * ?
     * 
     * @param key
     *            ?
     * @param cache
     * @author 
     * @date 2015-10-28 ?3:19:58
     */
    private boolean deleteCaceh(String key, Cacheable cache) {
        Integer expire = THREAD_CACHE_EXPIRE.get();
        if (expire != null && expire > 0) {
            redisTemplate.expire(key, expire);
            return true;
        }
        return redisTemplate.del(key);
    }

    /**
     * ??
     * 
     * @param value
     *            ???
     * @return List<String>
     * @author 
     * @date 2015-10-18 ?10:05:42
     */
    private List<String> getCollectionString(Object value) {
        JSONArray arr = JSONUtils.parseArray(value);
        // JSONUtils.toJSONArray(JSONUtils.toJSONString(value));
        List<String> valArr = new ArrayList<String>(arr.size());
        for (int i = 0; i < arr.size(); i++) {
            valArr.add(JSONUtils.toJSONString(arr.get(i)));
        }
        return valArr;
    }

    /**
     * ??JSON?
     * 
     * @param arr
     *            ???
     * @return List<Object>
     * @author 
     * @date 2015-10-18 ?3:40:29
     */
    private List<Object> getCollectionJSON(Collection<String> arr, Cacheable cache) {
        List<Object> os = new ArrayList<Object>(arr.size());
        JSONObject json;
        Class<?> clazz = cache.returnMode();
        for (String s : arr) {
            try {
                json = JSONUtils.parse(s);
                if (clazz.isAssignableFrom(Boolean.class)) {
                    os.add(json);
                } else {
                    os.add(JSONUtils.toBean(json, clazz));
                }
            } catch (Exception e) {
                os.add(s);
            }
        }
        return os;
    }

    /**
     * ?
     * 
     * @param clazz
     *            ?
     * @param value
     *            
     * @return Object
     * @author 
     * @date 2015-10-16 ?8:26:35
     */
    @SuppressWarnings("unchecked")
    private Object castValue(Class<?> clazz, Object value) {
        if (value == null) {
            return value;
        }

        // ?
        if (List.class.isAssignableFrom(clazz)) {
            return value;
        }

        // ?
        if (Set.class.isAssignableFrom(clazz)) {
            Set<Object> ss = new HashSet<Object>();
            ss.addAll((List<Object>) value);
            return value;
        }

        // JSON
        if (clazz.isAssignableFrom(ResponseModel.class)) {
            return MsgProperties.getSuccess(value);
        }

        // 
        if (clazz.isAssignableFrom(String.class)) {
            return value.toString();
        }

        // JSON
        if (clazz.isAssignableFrom(JSONObject.class)) {
            return JSONUtils.parse(value.toString());
        }

        // Object
        if (clazz.isAssignableFrom(Object.class)) {
            return value;
        }
        try {
            // 
            return JSONUtils.toBean(JSONUtils.parse(value.toString()), clazz);
        } catch (Exception e) {
            return TypeUtils.cast(value, clazz, ParserConfig.getGlobalInstance());
        }
    }
}