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

目录
  • 一:模式说明
  • 二:项目实战
  • 三:源代码

一:模式说明

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

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

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

通用类图如下:

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,减少了数据库的直接访问。

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

说明:抽象类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;
	}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java经典设计模式之责任链模式原理与用法详解

    本文实例讲述了Java经典设计模式之责任链模式.分享给大家供大家参考,具体如下: 责任链模式:多个对象由其对象对应下家的引用连成一条链,请求在这个链上传递,直到链上的某一个接收对象处理此请求.因为请求的客户端并不知道链上最终是谁来处理这个请求,使得系统可以在不影响客户端的情况下动态地重新组织和分配责任,从而避免了请求发送者与请求处理者之间的耦合. 责任链械中涉及到三种角色: 1,抽象处理者角色 2,具体处理者角色 3,请求发送者 小例子:假设去买房子,买房子就需要砍价, 卖房的人职位不同,可以优

  • 详解Java实现设计模式之责任链模式

    一.模拟业务需求 假设我们现在需要在我们的系统中导入一批关于学生信息的Excel的数据,其主要的信息有:学号.姓名.年龄.性别等等,在导入系统的时候,我们肯定不能直接的保存到数据库,我们肯定是先要对这个Excel的数据进行校验,看是否符合系统的要求,只有都符合了系统的要求了,我们把这些数据保存到数据库中去.假如我们的学生对应的实体类如下: @Data public class Student { /** * 学生编号 */ private String stNo; /** * 学生姓名 */ p

  • Java设计模式之责任链模式(Chain of Responsibility模式)介绍

    Chain of Responsibility定义:Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合,唯一共同点是在他们之间传递request.也就是说,来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递到C类处理,就这样象一个链条(chain)一样传递下去. 如何使用责任链模式 虽然这一段是如何使用CoR,但是也是演示什么是CoR. 有一个Handler接口: 复制代码

  • 一文搞懂Java设计模式之责任链模式

    简述: 前端时间再看一些类库的源码,发现责任链模式的强大之处,尤其是和建造者模式的结合后强大的动态可扩展性更是牛逼的一塌糊涂.接下来赶紧了解一下吧! 我们先来了解一下什么是责任链模式: 职责链模式(Chain of Responsibility):使多个对象都有机会处理同一个请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 应用场景: 为完成同一个请求,如果存在多个请求处理器以及未知请求处理器个数或者请求处理器可动态配置的

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

    目录 一:模式说明 二:项目实战 三:源代码 一:模式说明 模式定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止. 责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果(取自<设计模式之禅>). 翻译:Client对象调用一个处理者(类)的方法,可能有多个处理者(实现类),但是该对象只需要调用第一个处理者(类)即可,该模式会自动分配谁来处理这个请求:这

  • Java设计模式之责任链模式的概念、实现以及netty中的责任链模式

    本文先介绍了责任链模式的概念及简单实现.再贴了netty中对责任链的实现.最后总结了一点点思考. 1.概念相关 1.1.概念 责任链模式为请求创建了一个接收者对象的链,每个接收者都包含对另一个接收者的引用.如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,沿着这条链传递请求,直到有对象处理它为止. 1.2.解决了什么: 客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了. 1.3.场景: 1.有多个对象可以处理同一

  • Java 设计模式之责任链模式及异步责任链详解

    目录 一.定义 二.普通责任链模式 三.异步责任链模式 一.定义 责任链模式(Chain of Responsibility Pattern):避免将一个请求的发送者与接受者耦合在一起,让多个对象都有机会处理请求.将接受请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止. 在很多源码都有涉及,如Mybatis拦截器.Filter- 责任链模式属于行为型模式. 二.普通责任链模式 抽象处理类:AbstractProcessor /** * 抽象处理类 */ public

  • Java设计模式之责任链模式的示例详解

    目录 应用场景 实际代码案例 无模式情况下的代码 采用责任链模式优化代码 采用建造者+责任链模式优化代码 责任链模式优缺点 责任链模式是将链中的每一个节点看做是一个对象,每个节点处理的请求均不相同,且内部自动维护下一个节点对象,当一个请求从链式的首段发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求位置,属于行为模式. 这里需要注意的是每个节点都能对对象进行一定的处理(也可以不处理),处理完成之后节点再进行判断还要进行后续处理还是说传递给下一个节点. 应用场景 首先举一个日常

  • Java设计模式中责任链模式详解

    目录 1.责任链设计模式的定义 2.责任链设计模式的优点与不足 3.责任链设计模式的实现思路 4.责任链设计模式应用实例 5.责任链设计模式应用场景 编程是一门艺术,大批量的改动显然是非常丑陋的做法,用心的琢磨写的代码让它变的更美观. 在现实生活中,一个事件需要经过多个对象处理是很常见的场景.例如,采购审批流程.请假流程等.公司员工请假,可批假的领导有部门负责人.副总经理.总经理等,但每个领导能批准的天数不同,员工必须根据需要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名.电话

  • Java设计模式之责任链模式

    设计者往往会用拦截器去代替动态代理,然后将拦截器的接口提供给开发者,从而简化开发者的开发难度,但是拦截器可能有多个.举个例子,一个程序员需要请假一周,如果把请假申请单看成一个对象,那么它需要经过项目经理.部门经理.人事等多个角色的审批,每个角色都有机会通过拦截这个申请单进行审批或者修改.这事就要考虑提供项目经理.部门经理和人事的处理逻辑,所以需要提供3个拦截器,二传递的则是请假申请单. 当一个对象在一条链上被多个拦截器处理(拦截器也可以选择不拦截处理它)时,我们把这样的设计模式成为责任链模式,它

  • JAVA设计模式之责任链模式详解

    在阎宏博士的<JAVA与模式>一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任. 从击鼓传花谈起 击鼓传花是一种热闹而又紧张的饮酒游戏.在酒宴上宾客依次坐定位置,由一人击鼓,击鼓

  • Java设计模式之责任链模式简介

    对于使用过宏的朋友应该知道,利用宏可以实现一个键绑定多个技能.例如如果排在前面的技能有CD,则跳过此技能,执行之后的技能.记得曾经玩DK,打怪的时候,就是用一个键,一直按就行了.在servlet里的doGet和doPost方法,我们一般都把doGet请求发动到doPost里来处理,这也是一种责任链的模式. 这里,有个宏,绑定了"冰血冷脉"和"寒冰箭"两个技能,程序实例如下所示: package responsibility; /** * DOC 技能接口,要绑定的技

随机推荐