当前位置:   article > 正文

设计模式(实战)-责任链模式_责任链模式实战的实现方式

责任链模式实战的实现方式

一:模式说明

模式定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果(取自《设计模式之禅》)。

翻译:Client对象调用一个处理者(类)的方法,可能有多个处理者(实现类),但是该对象只需要调用第一个处理者(类)即可,该模式会自动分配谁来处理这个请求;这多个处理者继承同一个父类(即在一条链上)。

通用类图如下:

Client发送请求到Handler,Handler自动分配请求到子类的实现类ConcreteHandler中。

 

二:项目实战

    在文章 >手写redis@Cacheable注解 支持过期时间设置< 的基础之上做修改,原版为redis缓存注解实现,

    原版实现功能:

  1. 将数据存放到redis中 
  2. 设置过期时间  

     原业务逻辑查询人员列表listleader()接口,数据存放redis中,减少数据库负载。

     由于业务发展,需要进一步优化查询接口;目前每个人都会操作redis中存放的人员列表,导致该列表会实时发生变动(比如

每个人员对应的分数),每个人都有自己的缓存人员列表而不是统一的人员列表;原列表已经无法满足现需求,每个人第一次登

录都会查询数据库,将自己的列表存放在redis中。

    解决方法:设置两级缓存,第一级为该用户(uuid)唯一缓存,key值设置为参数1+uuid+参数2;第二级为第一次登录查询返  

回redis中的原始leader列表,key值设置为参数1+参数2。如果当前用户leader列表(一级缓存)为空,则查询原始leader列表

(二级缓存),在操作分数的时候修改二级缓存(初始人员列表)来产生一级缓存,存放进redis,减少了数据库的直接访问。

项目中责任链相关设计类图如下:

说明:抽象类CacheHandler 一是定义了处理请求方法handleMessage;二是定义一个链的编排方法setNext,设置下一个处理者;三是定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别getHandlerLevel和具体的处理任务response;

FirstCacheHadler为一级缓存处理者,SecondCacheHadler为二级缓存处理者。缓存处理的方式通过CacheableAspect类调用。

 

三:源代码

CacheableAspect:client调用

  1. package com.huajie.aspect;
  2. import java.lang.reflect.Method;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import org.aspectj.lang.ProceedingJoinPoint;
  6. import org.aspectj.lang.annotation.Around;
  7. import org.aspectj.lang.annotation.Aspect;
  8. import org.aspectj.lang.annotation.Pointcut;
  9. import org.aspectj.lang.reflect.MethodSignature;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.stereotype.Component;
  12. import com.huajie.annotation.ExtCacheable;
  13. import com.huajie.common.cache.CacheHandler;
  14. import com.huajie.common.cache.FirstCacheHadler;
  15. import com.huajie.common.cache.RedisResult;
  16. import com.huajie.common.cache.SecondCacheHadler;
  17. import com.huajie.utils.RedisUtil;
  18. import com.huajie.utils.StringUtil;
  19. /**
  20. * redis缓存处理 不适用与内部方法调用(this.)或者private
  21. */
  22. @Component
  23. @Aspect
  24. public class CacheableAspect {
  25. @Autowired
  26. private RedisUtil redisUtil;
  27. @Pointcut("@annotation(com.huajie.annotation.ExtCacheable)")
  28. public void annotationPointcut() {
  29. }
  30. @Around("annotationPointcut()")
  31. public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
  32. // 获得当前访问的class
  33. Class<?> className = joinPoint.getTarget().getClass();
  34. // 获得访问的方法名
  35. String methodName = joinPoint.getSignature().getName();
  36. // 得到方法的参数的类型
  37. Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
  38. Object[] args = joinPoint.getArgs();
  39. String key = "";
  40. String nextKey = "";
  41. int expireTime = 1800;
  42. try {
  43. // 得到访问的方法对象
  44. Method method = className.getMethod(methodName, argClass);
  45. method.setAccessible(true);
  46. // 判断是否存在@ExtCacheable注解
  47. if (method.isAnnotationPresent(ExtCacheable.class)) {
  48. ExtCacheable annotation = method.getAnnotation(ExtCacheable.class);
  49. key = getRedisKey(args, annotation.key());
  50. nextKey = getRedisKey(args,annotation.nextKey());
  51. expireTime = getExpireTime(annotation);
  52. }
  53. } catch (Exception e) {
  54. throw new RuntimeException("redis缓存注解参数异常", e);
  55. }
  56. //责任链模式
  57. CacheHandler firstCacheHadler = new FirstCacheHadler();
  58. CacheHandler secondCacheHadler = new SecondCacheHadler();
  59. //设置下级处理者
  60. firstCacheHadler.setNext(secondCacheHadler);
  61. //获取处理级别
  62. int cacheLevel = getCacheLevel(key, nextKey);
  63. RedisResult result = new RedisResult(redisUtil, key, nextKey, joinPoint, cacheLevel, expireTime);
  64. //客户端调用
  65. return firstCacheHadler.HandleMessage(result);
  66. }
  67. private int getCacheLevel(String key, String nextKey) {
  68. if (StringUtil.isNotEmpty(key) && StringUtil.isNotEmpty(nextKey)) {
  69. return 2;
  70. } else {
  71. return 1;
  72. }
  73. }
  74. private int getExpireTime(ExtCacheable annotation) {
  75. return annotation.expireTime();
  76. }
  77. private String getRedisKey(Object[] args, String primalKey) {
  78. // 获取#p0...集合
  79. List<String> keyList = getKeyParsList(primalKey);
  80. for (String keyName : keyList) {
  81. int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", ""));
  82. Object parValue = args[keyIndex];
  83. primalKey = primalKey.replace(keyName, String.valueOf(parValue));
  84. }
  85. return primalKey.replace("+", "").replace("'", "");
  86. }
  87. // 获取key中#p0中的参数名称
  88. private static List<String> getKeyParsList(String key) {
  89. List<String> ListPar = new ArrayList<String>();
  90. if (key.indexOf("#") >= 0) {
  91. int plusIndex = key.substring(key.indexOf("#")).indexOf("+");
  92. int indexNext = 0;
  93. String parName = "";
  94. int indexPre = key.indexOf("#");
  95. if (plusIndex > 0) {
  96. indexNext = key.indexOf("#") + key.substring(key.indexOf("#")).indexOf("+");
  97. parName = key.substring(indexPre, indexNext);
  98. } else {
  99. parName = key.substring(indexPre);
  100. }
  101. ListPar.add(parName.trim());
  102. key = key.substring(indexNext + 1);
  103. if (key.indexOf("#") >= 0) {
  104. ListPar.addAll(getKeyParsList(key));
  105. }
  106. }
  107. return ListPar;
  108. }
  109. }

CacheHandler:

  1. package com.huajie.common.cache;
  2. /**
  3. * @author xiewenfeng 缓存处理接口
  4. * 责任链模式
  5. */
  6. public abstract class CacheHandler {
  7. // 定义处理级别
  8. protected final static int FirstCache_LEVEL_REQUEST = 1;
  9. protected final static int SecondCache_LEVEL_REQUEST = 2;
  10. // 能处理的级别
  11. private int level = 0;
  12. // 责任传递,下一个责任人是谁
  13. private CacheHandler nextHandler;
  14. // 每个类自己能处理那些请求
  15. public CacheHandler(int level) {
  16. this.level = level;
  17. }
  18. // 处理请求
  19. public final Object HandleMessage(RedisResult redisResult) throws Throwable {
  20. //如果women类型为当前处理的level
  21. if(redisResult.getCacheLevel()==this.level){
  22. return this.response(redisResult);
  23. }else{
  24. if(null!=this.nextHandler){
  25. return this.nextHandler.HandleMessage(redisResult);
  26. }else{
  27. //没有下级不处理
  28. return null;
  29. }
  30. }
  31. }
  32. public void setNext(CacheHandler handler) {
  33. this.nextHandler = handler;
  34. }
  35. // 有请示的回应
  36. protected abstract Object response(RedisResult redisResult) throws Throwable;
  37. }

FirstCacheHadler:一级缓存处理者

  1. package com.huajie.common.cache;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import com.huajie.utils.RedisUtil;
  4. public class FirstCacheHadler extends CacheHandler{
  5. public FirstCacheHadler() {
  6. super(CacheHandler.FirstCache_LEVEL_REQUEST);
  7. }
  8. @Override
  9. protected Object response(RedisResult redisResult) throws Throwable {
  10. String key = redisResult.getKey();
  11. RedisUtil redisUtil = redisResult.getRedisUtil();
  12. boolean hasKey = redisUtil.hasKey(key);
  13. ProceedingJoinPoint joinPoint = redisResult.getJoinPoint();
  14. int expireTime = redisResult.getExpireTime();
  15. if (hasKey) {
  16. return redisUtil.get(key);
  17. } else {
  18. Object res = joinPoint.proceed();
  19. redisUtil.set(key, res);
  20. redisUtil.expire(key, expireTime);
  21. return res;
  22. }
  23. }
  24. }

SecondCacheHadler:二级缓存处理者

  1. package com.huajie.common.cache;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import com.huajie.utils.RedisUtil;
  4. public class SecondCacheHadler extends CacheHandler {
  5. public SecondCacheHadler() {
  6. super(CacheHandler.SecondCache_LEVEL_REQUEST);
  7. }
  8. @Override
  9. protected Object response(RedisResult redisResult) throws Throwable {
  10. String nextKey = redisResult.getNextKey();
  11. String key = redisResult.getKey();
  12. RedisUtil redisUtil = redisResult.getRedisUtil();
  13. ProceedingJoinPoint joinPoint = redisResult.getJoinPoint();
  14. int expireTime = redisResult.getExpireTime();
  15. boolean hasKey = redisUtil.hasKey(key);
  16. if (hasKey) {
  17. return redisUtil.get(key);
  18. } else {
  19. boolean hasNextKey = redisUtil.hasKey(nextKey);
  20. if (hasNextKey) {
  21. return redisUtil.get(nextKey);
  22. } else {
  23. Object res = joinPoint.proceed();
  24. redisUtil.set(nextKey, res);
  25. redisUtil.expire(nextKey, expireTime);
  26. return res;
  27. }
  28. }
  29. }
  30. }

RedisResult:该业务场景对象,用于传递参数

  1. package com.huajie.common.cache;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import com.huajie.utils.RedisUtil;
  4. import lombok.Data;
  5. @Data
  6. public class RedisResult implements IRedisResult {
  7. private int cacheLevel;
  8. private Object result;
  9. private RedisUtil redisUtil;
  10. private String key;
  11. private String nextKey;
  12. private int expireTime;
  13. private ProceedingJoinPoint joinPoint;
  14. @Override
  15. public int getCacheLevel() {
  16. return cacheLevel;
  17. }
  18. @Override
  19. public Object getResult() {
  20. return result;
  21. }
  22. public RedisResult(RedisUtil redisUtil, String key, String nextKey, ProceedingJoinPoint joinPoint, int cacheLevel,int expireTime) {
  23. this.redisUtil = redisUtil;
  24. this.key = key;
  25. this.joinPoint = joinPoint;
  26. this.cacheLevel = cacheLevel;
  27. this.nextKey = nextKey;
  28. this.expireTime = expireTime;
  29. }
  30. }

使用方法如下:

  1. @Override
  2. @ExtCacheable(key = "middle+#p0+#p1+#p2", nextKey = "middle+#p0+#p2")
  3. public List<MiddleManage> listMiddleManageInfo(String leadergroupId, String uuid, String yearDetailId) {
  4. Map<String, Object> map = new HashMap<String, Object>();
  5. map.put("leadergroupId", leadergroupId);
  6. map.put("uuid", uuid);
  7. map.put("yearDetailId", yearDetailId);
  8. List<MiddleManage> middleManageDetailList = middleManageMapper.listMiddleManageInfo(map);
  9. return middleManageDetailList;
  10. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/497900
推荐阅读
相关标签
  

闽ICP备14008679号