spring aop实现注解式缓存

来源:互联网 发布:双色球参选数据真的吗 编辑:程序博客网 时间:2024/06/08 18:21

    场景:根据键到缓存中取数据,缓存中没有则从数据库获取,获取后又存进缓存,于是:

  1.   private CacheClient cacheClient;
  2.   ……
  3.   public String bindInfo(String organCode, Long userId) {
  4.        String cacheKey = ……;
  5.        String cacheData = (String) cacheClient.get(cacheKey);
  6.        if (cacheData != null) {
  7.            return cacheData;
  8.        } else {
  9.            ……
  10.            String data = sessionTemplate.selectOne(……, ……);
  11.            if (data != null) {
  12.                cacheClient.set(cacheKey, data);
  13.            }
  14.            return data;
  15.        }
  16.    }

上述代码很常见,写到烦。

懒人懒招:

        1、自定义缓存与清除缓存注解

        2、mvel合成cacheKey

一、缓存注解与aop

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target({ElementType.METHOD})
  3. @Documented
  4. public @interface CacheConfig {
  5.    String template() default "";//缓存键值模板
  6.    String[] expression() default {};//获取缓存键值表达式
  7.    int expires() default -1;//过期时间
  8. }

  1. @Component
  2. @Aspect
  3. public class CacheConfigAspect {
  4.    private static final Logger logger = LoggerFactory.getLogger(CacheConfigAspect.class);
  5.    @Autowired
  6.    private CacheClient cacheClient;
  7.    private static CacheMap<String, Class> returnTypeCache = new LFUCache<String, Class>(1000, 2 * 60 * 1000);
  8.    @Pointcut(value = "@annotation(com.yiwuliu.cache.annotations.CacheConfig) && @annotation(cacheConfig)")
  9.    public void cacheConfigAspect(CacheConfig cacheConfig) {
  10.    }
  11.    @Around(value = "cacheConfigAspect(cacheConfig)")
  12.    public Object needCacheAround(ProceedingJoinPoint joinPoint, CacheConfig cacheConfig) {
  13.        Object data = null;
  14.        try {
  15.            String template = cacheConfig.template();
  16.            String[] expressions = cacheConfig.expression();
  17.            Object[] params = joinPoint.getArgs();
  18.            String cacheKey = AssembleUtil.assembleCacheKey(template, expressions, params);
  19.            Class clazz = returnTypeCache.get(joinPoint.toLongString());
  20.            if (!Strings.isNullOrEmpty(cacheKey) && null != clazz) {
  21.                data = getDataFromCache(clazz, cacheKey);
  22.            }
  23.            if (null == data) {
  24.                data = getDataFromDB(joinPoint, cacheConfig, cacheKey);
  25.            }
  26.        } catch (Throwable e) {
  27.            logger.error("{} failed to get info from cache in result of {}", joinPoint.getSignature().toLongString(),
  28.                         e.toString());
  29.        }
  30.        return data;
  31.    }
  32. }

二、缓存清除注解与aop

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target({ElementType.METHOD})
  3. @Documented
  4. public @interface CacheClear {
  5.    String template() default "";//缓存键值模板
  6.    String[] expressions() default {};//获取缓存键值表达式
  7. }
  1. @Component
  2. @Aspect
  3. public class CacheClearAspect {
  4.    private static final Logger logger = LoggerFactory.getLogger(CacheClearAspect.class);
  5.    @Autowired
  6.    private CacheClient cacheClient;
  7.    @Pointcut(value = "@annotation(com.yiwuliu.cache.annotations.CacheClear) && @annotation(cacheClear)")
  8.    public void cacheClearAspect(CacheClear cacheClear) {
  9.    }
  10.    @Around(value = "cacheClearAspect(cacheClear)")
  11.    public Object clearAspect(ProceedingJoinPoint joinPoint, CacheClear cacheClear) {
  12.        Object result = null;
  13.        try {
  14.            String template = cacheClear.template();
  15.            String[] expressions = cacheClear.expressions();
  16.            Object[] params = joinPoint.getArgs();
  17.            result = joinPoint.proceed(params);
  18.            String cacheKey = AssembleUtil.assembleCacheKey(template, expressions, params);
  19.            cacheClient.delete(cacheKey);
  20.            logger.debug("CacheClearsAspect Remove From Cache : {}", cacheKey);
  21.        } catch (Throwable throwable) {
  22.            throwable.printStackTrace();
  23.        }
  24.        return result;
  25.    }
  26. }

三、AssembleUtil合成CacheKey

  1. public final class AssembleUtil {
  2.    private static final String SEPARATOR = ":";
  3.    public static List<String> assembleCacheKeys(String[] templates, String[] expressions,
  4.                                                 Object[] params) throws Exception {
  5.        List<java.lang.String> cacheKeys = Lists.newArrayList();
  6.        expressions = templateValues(expressions, params);
  7.        for (java.lang.String template : templates) {
  8.            cacheKeys.add(MessageFormat.format(template, expressions));
  9.        }
  10.        return cacheKeys;
  11.    }
  12.    public static String assembleCacheKey(String template, String[] expressions, Object[] params) throws Exception {
  13.        return MessageFormat.format(template, templateValues(expressions, params));
  14.    }
  15.    private static String[] templateValues(String[] expressions, Object[] params) {
  16.        for (int i = 0; i < expressions.length; i++) {
  17.            java.lang.String[] split = expressions[i].split(SEPARATOR);
  18.            int argsIndex = Integer.parseInt(split[0]) - 1;
  19.            if (split.length == 1) {
  20.                expressions[i] = java.lang.String.valueOf(params[argsIndex]);
  21.            } else {
  22.                expressions[i] = java.lang.String.valueOf(MVEL.eval(split[1], params[argsIndex]));
  23.            }
  24.        }
  25.        return expressions;
  26.    }
  27. }

四、怎么用???

1、spring文件中加入aop:aspect-autoproxy配置,依赖org.aspectj:aspectjweaver、org.aspectj:aspectjrt 

  1. <aop:aspectj-autoproxy expose-proxy="true"/>

2、给需要缓存结果的方法加注解

  1. @CacheConfig(template = "phone:bind:{0}:{1}", expression = {"1", "2"})
  2. public OpenUserModel bindInfo(String organCode, Long userId) {
  3.    Map<String, Object> params = Maps.newHashMap();
  4.    params.put(ParamsKey.ORGAN_CODE, organCode);
  5.    params.put(ParamsKey.USER_ID, userId);
  6.    return sessionTemplate.selectOne("phone.bind.bindInfo", params);
  7. }

3、给需要清除缓存的方法加注解

  1. @CacheClear(template = "phone:bind:{0}:{1}", expressions = {"1:organCode", "1:userId"})
  2. public void bind(OpenUserModel openUserModel) {
  3.    sessionTemplate.insert(……, ……);
  4. }

纯粹小白,欢迎路过大神指正!













0 0
原创粉丝点击