CacheInterceptorImpl.java 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /** Copyright 2009 by primeton Corporation.
  2. *
  3. * All rights reserved.
  4. *
  5. * This software is the confidential and proprietary information of
  6. * primeton Corporation ('Confidential Information'). You
  7. * shall not disclose such Confidential Information and shall use
  8. * it only in accordance with the terms of the license agreement
  9. * you entered into with primeton.
  10. */
  11. package com.primeton.dgs.kernel.core.cache.impl;
  12. import java.lang.reflect.Method;
  13. import java.security.MessageDigest;
  14. import java.util.HashMap;
  15. import java.util.Map;
  16. import com.primeton.dgs.kernel.core.cache.CacheEvict;
  17. import com.primeton.dgs.kernel.core.cache.Cacheable;
  18. import com.primeton.dgs.kernel.core.util.StringFullUtils;
  19. import org.apache.commons.lang.StringUtils;
  20. import org.apache.commons.lang3.SystemUtils;
  21. import org.aspectj.lang.ProceedingJoinPoint;
  22. import com.primeton.dgs.kernel.core.cache.ICache;
  23. import com.primeton.dgs.kernel.core.cache.ICacheInterceptor;
  24. import com.primeton.dgs.kernel.core.cache.ICacheKeyCreator;
  25. import org.aspectj.lang.Signature;
  26. import org.aspectj.lang.reflect.MethodSignature;
  27. import org.slf4j.Logger;
  28. import org.slf4j.LoggerFactory;
  29. /**
  30. * @author xiongbin
  31. * @author zhaopx 缓存拦截器
  32. * @Version 2012-8-28
  33. */
  34. public class CacheInterceptorImpl implements ICacheInterceptor {
  35. private static final Logger log = LoggerFactory.getLogger(CacheInterceptorImpl.class);
  36. /**
  37. * 缓存
  38. */
  39. private ICache<Object> cache;
  40. /**
  41. * 缓存的 Key 生成逻辑管理器
  42. */
  43. private DefaultCacheKeyCreatorManager manager;
  44. public Object add(ProceedingJoinPoint jp){
  45. try {
  46. Object[] args = jp.getArgs();
  47. // 通过 AOP 拦截的类全名,获得该类的 ICacheKeyCreator,缓存 ID 生成器
  48. // ICacheKeyCreator 一定是非空的
  49. ICacheKeyCreator creator = manager.getCacheKeyCreator(jp.getTarget().getClass().getName());
  50. // 获取到该方法需要缓存的 Name
  51. String methodName = jp.getSignature().getName();
  52. // 通过参数生成缓存 ID
  53. String key = getKey(creator.getCacheKey(args));
  54. if(StringUtils.isNotBlank(key)){
  55. final String cacheKey = methodName + "_" + key;
  56. synchronized (this) {
  57. Object result = cache.get(cacheKey);
  58. if(result == null){
  59. result = jp.proceed();
  60. // 调用取得返回值缓存,如果是从缓存中取出,无须继续放入缓存,减少
  61. cache.add(cacheKey, creator.getExpTime(methodName), result);
  62. }
  63. return result;
  64. }
  65. }
  66. // 无参数函数无法缓存,或者缓存的 Key 无法生成,不缓存
  67. return jp.proceed();
  68. } catch (Throwable e) {
  69. log.error("AOP 调用接口异常。", e);
  70. throw new IllegalStateException(e);
  71. }
  72. }
  73. /**
  74. * 根据 接口的注解支持缓存
  75. *
  76. * add zhaopx at: 2019/09/24
  77. * @param jp
  78. * @return
  79. */
  80. public Object cachedAnno(ProceedingJoinPoint jp){
  81. try {
  82. Object[] args = jp.getArgs();
  83. Class<?> aClass = jp.getTarget().getClass();
  84. Signature signature = jp.getSignature();
  85. String methodName = signature.getName();
  86. MethodSignature msig = null;
  87. if (!(signature instanceof MethodSignature)) {
  88. throw new IllegalArgumentException("该注解只能用于方法");
  89. }
  90. msig = (MethodSignature) signature;
  91. Class[] parameterTypes = msig.getParameterTypes();
  92. Method cachedMethod = aClass.getMethod(msig.getName(), parameterTypes);
  93. // 方法参数,构成一个 Map,用于拼接 Cache key
  94. final Map<String, String> argsMap = new HashMap<>(parameterTypes.length);
  95. argsMap.put("methodName", methodName);
  96. argsMap.put("className", aClass.getSimpleName());
  97. for (int i = 0; i < args.length; i++) {
  98. String argValue = (args[i] == null ? "" : String.valueOf(args[i]));
  99. argsMap.put("arg" + i, argValue);
  100. }
  101. // JDK8 才执行
  102. if(SystemUtils.IS_JAVA_1_8) {
  103. int i = 0;
  104. // 这样的方式导入,否则 JDK7 一下报错
  105. java.lang.reflect.Parameter[] parameters = cachedMethod.getParameters();
  106. for (java.lang.reflect.Parameter parameter : parameters) {
  107. String argValue = (args[i] == null ? "" : String.valueOf(args[i]));
  108. argsMap.put(parameter.getName(), argValue);
  109. i++;
  110. }
  111. }
  112. // 删除缓存的策略
  113. CacheEvict cacheEvictAnno = cachedMethod.getAnnotation(CacheEvict.class);
  114. if(cacheEvictAnno != null) {
  115. if(cacheEvictAnno.allEntries()) {
  116. // 删除所有缓存键
  117. cache.clear();
  118. } else {
  119. String[] keys = cacheEvictAnno.keys();
  120. for (String key : keys) {
  121. // 依次删除所有缓存 Key
  122. // 宏替换,替换 ${} 内的变量
  123. key = StringFullUtils.getFullString(key, argsMap);
  124. cache.remove(key);
  125. log.warn("remove cache key {}", key);
  126. }
  127. // 前缀删除,当前还看怎么支持
  128. if(StringUtils.isNotBlank(cacheEvictAnno.keyPrefix())) {
  129. try {
  130. cache.removeByPrefix(cacheEvictAnno.keyPrefix());
  131. } catch (Exception e) {}
  132. }
  133. }
  134. }
  135. // 获取方法注解
  136. Cacheable cachedAnno = cachedMethod.getAnnotation(Cacheable.class);
  137. if(cachedAnno == null) {
  138. // 接口上没有 Cacheable 的注解,不进行缓存
  139. // log.info("execute no cache method {}.{}", aClass.getName(), methodName);
  140. // 无参数函数无法缓存,或者缓存的 Key 无法生成,不缓存
  141. return jp.proceed();
  142. } else {
  143. final long start = System.currentTimeMillis();
  144. String key = cachedAnno.key();
  145. // 宏替换,替换 ${} 内的变量
  146. key = StringFullUtils.getFullString(key, argsMap);
  147. Object result = cache.get(key);
  148. if(result == null){
  149. log.info("no cache key {}, execute method {}.{}", key, aClass.getName(), methodName);
  150. result = jp.proceed();
  151. if(cachedAnno.expire() > 0) {
  152. // 有缓存过期时间的
  153. cache.add(key, cachedAnno.expire(), result);
  154. } else {
  155. cache.add(key, result);
  156. }
  157. } else {
  158. log.info("cached key {}, return result from cache(exe {}, cost time {} ms).",
  159. key,
  160. methodName,
  161. (System.currentTimeMillis() - start));
  162. }
  163. return result;
  164. }
  165. } catch (Throwable e) {
  166. log.error("AOP 调用接口异常。", e);
  167. throw new IllegalStateException(e.getMessage());
  168. }
  169. }
  170. private String getKey(String key) {
  171. if(key.matches("[*:]")){
  172. return "";
  173. }
  174. System.out.println("memcachedKEY:"+key);
  175. try {
  176. key = encryptMD5(key);
  177. } catch (Exception e) {
  178. log.error("生成 md5 异常。", e);
  179. }
  180. return key;
  181. }
  182. public void refresh() {
  183. try {
  184. cache.clear();
  185. } catch (Exception e) {
  186. log.error("清除缓存异常。", e);
  187. }
  188. }
  189. public DefaultCacheKeyCreatorManager getManager() {
  190. return manager;
  191. }
  192. public void setManager(DefaultCacheKeyCreatorManager manager) {
  193. this.manager = manager;
  194. }
  195. public ICache getCache() {
  196. return cache;
  197. }
  198. public void setCache(ICache cache) {
  199. this.cache = cache;
  200. }
  201. /**
  202. * 使用MD5加密
  203. * @param originalText 明文
  204. * @return 密文
  205. * @throws Exception JDK不支持MD5加密算法
  206. */
  207. private String encryptMD5(String originalText) throws Exception {
  208. MessageDigest md5 = MessageDigest.getInstance("MD5");
  209. md5.update(originalText.getBytes());
  210. byte[] digest = md5.digest();
  211. StringBuffer sb = new StringBuffer();
  212. for (int i = 0; i < digest.length; i++) {
  213. String s = Integer.toHexString(digest[i] & 0XFF);
  214. if (s.length() == 1) {
  215. sb.append(i).append(s);
  216. } else {
  217. sb.append(s);
  218. }
  219. if (i < digest.length-1) {
  220. sb.append(i);
  221. }
  222. }
  223. return sb.toString().toUpperCase();
  224. }
  225. }