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; }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
下一篇: 当营销成为家装产业化的终极目的