java设计模式(实战)-责任链模式

作者:不懂的浪漫 时间:2022-12-24 23:07:53 

一:模式说明

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

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

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

通用类图如下:

java设计模式(实战)-责任链模式

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

二:项目实战

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

原版实现功能:

  • 将数据存放到redis中 

  • 设置过期时间  

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

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

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

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

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

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

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

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

java设计模式(实战)-责任链模式

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

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

三:源代码

CacheableAspect:client调用

package com.huajie.aspect;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.huajie.annotation.ExtCacheable;
import com.huajie.common.cache.CacheHandler;
import com.huajie.common.cache.FirstCacheHadler;
import com.huajie.common.cache.RedisResult;
import com.huajie.common.cache.SecondCacheHadler;
import com.huajie.utils.RedisUtil;
import com.huajie.utils.StringUtil;

/**
* redis缓存处理 不适用与内部方法调用(this.)或者private
*/
@Component
@Aspect
public class CacheableAspect {

@Autowired
private RedisUtil redisUtil;

@Pointcut("@annotation(com.huajie.annotation.ExtCacheable)")
public void annotationPointcut() {
}

@Around("annotationPointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 获得当前访问的class
Class<?> className = joinPoint.getTarget().getClass();
// 获得访问的方法名
String methodName = joinPoint.getSignature().getName();
// 得到方法的参数的类型
Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
Object[] args = joinPoint.getArgs();
String key = "";
String nextKey = "";
int expireTime = 1800;
try {
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass);
method.setAccessible(true);
// 判断是否存在@ExtCacheable注解
if (method.isAnnotationPresent(ExtCacheable.class)) {
ExtCacheable annotation = method.getAnnotation(ExtCacheable.class);
key = getRedisKey(args, annotation.key());
nextKey = getRedisKey(args,annotation.nextKey());
expireTime = getExpireTime(annotation);
}
} catch (Exception e) {
throw new RuntimeException("redis缓存注解参数异常", e);
}
//责任链模式
CacheHandler firstCacheHadler = new FirstCacheHadler();
CacheHandler secondCacheHadler = new SecondCacheHadler();
//设置下级处理者
firstCacheHadler.setNext(secondCacheHadler);
//获取处理级别
int cacheLevel = getCacheLevel(key, nextKey);
RedisResult result = new RedisResult(redisUtil, key, nextKey, joinPoint, cacheLevel, expireTime);
//客户端调用
return firstCacheHadler.HandleMessage(result);
}

private int getCacheLevel(String key, String nextKey) {
if (StringUtil.isNotEmpty(key) && StringUtil.isNotEmpty(nextKey)) {
return 2;
} else {
return 1;
}
}

private int getExpireTime(ExtCacheable annotation) {
return annotation.expireTime();
}

private String getRedisKey(Object[] args, String primalKey) {
// 获取#p0...集合
List<String> keyList = getKeyParsList(primalKey);
for (String keyName : keyList) {
int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", ""));
Object parValue = args[keyIndex];
primalKey = primalKey.replace(keyName, String.valueOf(parValue));
}
return primalKey.replace("+", "").replace("'", "");
}

// 获取key中#p0中的参数名称
private static List<String> getKeyParsList(String key) {
List<String> ListPar = new ArrayList<String>();
if (key.indexOf("#") >= 0) {
int plusIndex = key.substring(key.indexOf("#")).indexOf("+");
int indexNext = 0;
String parName = "";
int indexPre = key.indexOf("#");
if (plusIndex > 0) {
indexNext = key.indexOf("#") + key.substring(key.indexOf("#")).indexOf("+");
parName = key.substring(indexPre, indexNext);
} else {
parName = key.substring(indexPre);
}
ListPar.add(parName.trim());
key = key.substring(indexNext + 1);
if (key.indexOf("#") >= 0) {
ListPar.addAll(getKeyParsList(key));
}
}
return ListPar;
}
}

CacheHandler:

package com.huajie.common.cache;
/**
* @author xiewenfeng 缓存处理接口
* 责任链模式
*/
public abstract class CacheHandler {
// 定义处理级别
protected final static int FirstCache_LEVEL_REQUEST = 1;
protected final static int SecondCache_LEVEL_REQUEST = 2;

// 能处理的级别
private int level = 0;
// 责任传递,下一个责任人是谁
private CacheHandler nextHandler;

// 每个类自己能处理那些请求
public CacheHandler(int level) {
this.level = level;
}

// 处理请求
public final Object HandleMessage(RedisResult redisResult) throws Throwable {
//如果women类型为当前处理的level
if(redisResult.getCacheLevel()==this.level){
return this.response(redisResult);
}else{
if(null!=this.nextHandler){
return this.nextHandler.HandleMessage(redisResult);
}else{
//没有下级不处理
return null;
}
}
}

public void setNext(CacheHandler handler) {
this.nextHandler = handler;
}

// 有请示的回应
protected abstract Object response(RedisResult redisResult) throws Throwable;
}

FirstCacheHadler:一级缓存处理者

package com.huajie.common.cache;
import org.aspectj.lang.ProceedingJoinPoint;
import com.huajie.utils.RedisUtil;
public class FirstCacheHadler extends CacheHandler{
public FirstCacheHadler() {
super(CacheHandler.FirstCache_LEVEL_REQUEST);
}

@Override
protected Object response(RedisResult redisResult) throws Throwable {
String key = redisResult.getKey();
RedisUtil redisUtil = redisResult.getRedisUtil();
boolean  hasKey = redisUtil.hasKey(key);
ProceedingJoinPoint joinPoint = redisResult.getJoinPoint();
int expireTime = redisResult.getExpireTime();
if (hasKey) {
return redisUtil.get(key);
} else {
Object res = joinPoint.proceed();
redisUtil.set(key, res);
redisUtil.expire(key, expireTime);
return res;
}
}
}

SecondCacheHadler:二级缓存处理者

package com.huajie.common.cache;
import org.aspectj.lang.ProceedingJoinPoint;
import com.huajie.utils.RedisUtil;
public class SecondCacheHadler extends CacheHandler {
public SecondCacheHadler() {
super(CacheHandler.SecondCache_LEVEL_REQUEST);
}

@Override
protected Object response(RedisResult redisResult) throws Throwable {
String nextKey = redisResult.getNextKey();
String key = redisResult.getKey();
RedisUtil redisUtil = redisResult.getRedisUtil();
ProceedingJoinPoint joinPoint = redisResult.getJoinPoint();
int expireTime = redisResult.getExpireTime();
boolean hasKey = redisUtil.hasKey(key);
if (hasKey) {
return redisUtil.get(key);
} else {
boolean hasNextKey = redisUtil.hasKey(nextKey);
if (hasNextKey) {
return redisUtil.get(nextKey);
} else {
Object res = joinPoint.proceed();
redisUtil.set(nextKey, res);
redisUtil.expire(nextKey, expireTime);
return res;
}
}
}
}

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

package com.huajie.common.cache;
import org.aspectj.lang.ProceedingJoinPoint;
import com.huajie.utils.RedisUtil;
import lombok.Data;

@Data
public class RedisResult implements IRedisResult {
private int cacheLevel;
private Object result;
private RedisUtil redisUtil;
private String key;
private String nextKey;
private int expireTime;
private ProceedingJoinPoint joinPoint;

@Override
public int getCacheLevel() {
return cacheLevel;
}

@Override
public Object getResult() {
return result;
}

public RedisResult(RedisUtil redisUtil, String key, String nextKey, ProceedingJoinPoint joinPoint, int cacheLevel,int expireTime) {
this.redisUtil = redisUtil;
this.key = key;
this.joinPoint = joinPoint;
this.cacheLevel = cacheLevel;
this.nextKey = nextKey;
this.expireTime = expireTime;
}
}

使用方法如下:

@Override
@ExtCacheable(key = "middle+#p0+#p1+#p2", nextKey = "middle+#p0+#p2")
public List<MiddleManage> listMiddleManageInfo(String leadergroupId, String uuid, String yearDetailId) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("leadergroupId", leadergroupId);
map.put("uuid", uuid);
map.put("yearDetailId", yearDetailId);
List<MiddleManage> middleManageDetailList = middleManageMapper.listMiddleManageInfo(map);
return middleManageDetailList;
}

来源:https://blog.csdn.net/xiewenfeng520/article/details/83819487

标签:java,设计模式,责任链
0
投稿

猜你喜欢

  • SpringBoot集成MyBatis的分页插件PageHelper实例代码

    2023-09-11 21:54:33
  • Spring Boot 集成Shiro的多realm配置过程

    2023-09-17 10:07:26
  • java实现导出Excel的功能

    2022-07-17 15:57:28
  • JavaWeb开发之【Tomcat 环境配置】MyEclipse+IDEA配置教程

    2022-05-04 12:50:18
  • C# 执行CMD命令并接收返回结果的操作方式

    2023-09-03 10:36:56
  • springcloud整合seata的实现代码

    2022-04-26 23:49:49
  • ionic监听android返回键实现“再按一次退出”功能

    2021-12-24 10:22:57
  • Java Collections.shuffle()方法案例详解

    2023-11-24 15:53:16
  • java实现倾斜水印铺满整张图

    2023-12-24 22:34:21
  • Android自定义View实现等级滑动条的实例

    2023-12-08 19:57:53
  • c# 剔除sql语句'尾巴'的五种方法

    2022-09-20 16:32:39
  • Java深入了解数据结构之栈与队列的详解

    2022-03-24 08:12:27
  • myBatis组件教程之缓存的实现与使用

    2023-09-24 00:49:18
  • SpringMVC4 + MyBatis3 + SQL Server 2014整合教程(含增删改查分页)

    2023-09-27 01:47:32
  • android自定义倒计时控件示例

    2022-03-26 23:12:18
  • WinForm实现仿视频播放器左下角滚动新闻效果的方法

    2021-11-04 19:43:41
  • 关于Spring Boot内存泄露排查的记录

    2023-06-27 18:46:19
  • 如何使用Java爬虫批量爬取图片

    2023-01-11 16:19:54
  • Springboot使用@Valid 和AOP做参数校验及日志输出问题

    2023-12-05 04:39:12
  • java中transient关键字用法分析

    2022-01-22 04:27:05
  • asp之家 软件编程 m.aspxhome.com