Java tutorial
/* * @(#)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()); } } }