项目
博客
文档
归档
资源链接
关于我
项目
博客
文档
归档
资源链接
关于我
设计模式之 —— 责任链模式
2020-11-12
·
softbabet博主
·
原创
·
设计模式
·
本文共 668个字,预计阅读需要 3分钟。
## 责任链模式 职责链模式,为请求创建一个接收此次请求对象的链。行为型。 **为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。** 适用场景:一个请求的处理需要多个对象当中的一个或者几个协作处理。 优点:请求的发送者和接收者(请求的处理)解耦;责任链可以动态组合。 缺点:责任链太长或者处理时间过长,影响性能;责任链有可能过多。 相关设计模式: 责任链与状态模式:责任链模式中,各个对象并不指定下一个处理的对象者是谁,只有在客户端来设定这个链条中的顺序以及元素,直到被某个责任链元素处理或者整个链条结束。状态模式是让每个状态对象知道自己下一个处理的对象是谁,也就是说在编译时设定好了。 实体对象 ``` public class Course { private String name; private String article; private String video; //get set ... } ``` **责任链中重要的抽象类 -- 抽象处理者(Handler)-->setNext(自己类)类似于递归**, 此方法也可以变为实现一个抽象类含有deploy方法 ``` public abstract class Approver { protected Approver approver; public void setNextApprover(Approver approver){ this.approver =approver; } public abstract void deploy(Course course); } ``` **具体处理者1:每个责任的实现,其中最重要的是要判断执行的方法处:if(approver!=null){approver.deploy(course);}** ``` public class VideoApprover extends Approver { @Override public void deploy(Course course) { if(course.getVideo() !=null && !"".equals(course.getVideo())){ System.out.println(course.getName()+"含义视频,批准"); if(approver!=null){ approver.deploy(course); } }else { System.out.println(course.getName()+"不含有视频,不批准,流程结束"); return; } } } ``` 具体处理者2:另一个责任实现 ``` public class ArticApprover extends Approver { @Override public void deploy(Course course) { if(course.getArticle() !=null && !"".equals(course.getArticle())){ System.out.println(course.getName()+"含义手记,批准"); if(approver!=null){ approver.deploy(course); } }else { System.out.println(course.getName()+"不含有手记,不批准,流程结束"); return; } } } ``` 测试,可以在此处**定义每个责任执行的顺序**: ``` public static void main(String[] args) { ArticApprover articApprover = new ArticApprover(); VideoApprover videoApprover = new VideoApprover(); Course course = new Course(); course.setName("java精讲设计模式"); course.setArticle("java精讲手记"); course.setVideo("java精讲视频"); articApprover.setNextApprover(videoApprover); articApprover.deploy(course); } ``` 另外一种写法: ``` public interface IFilterShaoxi { void doFilter(Object request,Object response,IFilterShaoxi fc); } ``` ``` public class FirstFilter implements IFilterShaoxi { @Override public void doFilter(Object request,Object response,IFilterShaoxi fc) { System.out.println("=====first fitler before===="); String tmp =String.valueOf(request); tmp = tmp+"firstFilter"; fc.doFilter(tmp,response,fc); } } ``` ``` public class FilterChainShaoXi implements IFilterShaoxi { List
filterShaoxis=new ArrayList<>(); int index=0; public FilterChainShaoXi addFilter(IFilterShaoxi filterShaoxi){ filterShaoxis.add(filterShaoxi); return this; } @Override public void doFilter(Object request,Object response,IFilterShaoxi fc) { if(index == filterShaoxis.size()){ return ; } IFilterShaoxi filter = filterShaoxis.get(index); index++; filter.doFilter(request, response, fc); } } ``` ``` public static void main(String[] args) { FilterChainShaoXi filterChainShaoXi=new FilterChainShaoXi(); filterChainShaoXi.addFilter(new FirstFilter()); filterChainShaoXi.addFilter(new SecondFilter()); filterChainShaoXi.addFilter(new ThirdFilter()); filterChainShaoXi.addFilter(new WriteFilter()); filterChainShaoXi.doFilter("yandaye-","",filterChainShaoXi); } ``` ### 责任链模式源码应用 tomcat:Filter.doFilter() -->FilterChain ### 责任链模式实现的三种方式 #### servlet中的Filter servlet中分别定义了一个 Filter和FilterChain的接口,核心代码如下: ``` public final class ApplicationFilterChain implements FilterChain { private int pos = 0; //当前执行filter的offset private int n; //当前filter的数量 private ApplicationFilterConfig[] filters; //filter配置类,通过getFilter()方法获取Filter private Servlet servlet; @Override public void doFilter(ServletRequest request, ServletResponse response) { if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = filterConfig.getFilter(); filter.doFilter(request, response, this); } else { //filter都处理完毕后,执行servlet servlet.service(request, response); } } } ``` 代码还算简单,结构也比较清晰,定义一个Chain,里面包含了Filter列表和servlet,达到在调用真正servlet之前进行各种filter逻辑。 ![](http://114.67.107.180/ynblog/upload/1605170397639.png) #### Dubbo中的Filter Dubbo在创建Filter的时候是另外一个方法,通过把Filter封装成 Invoker的匿名类,通过链表这样的数据结构来完成责任链,核心代码如下: ``` private static
Invoker
buildInvokerChain(final Invoker
invoker, String key, String group) { Invoker
last = invoker; //只获取满足条件的Filter List
filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); if (filters.size() > 0) { for (int i = filters.size() - 1; i >= 0; i --) { final Filter filter = filters.get(i); final Invoker
next = last; last = new Invoker
() { public Result invoke(Invocation invocation) throws RpcException { return filter.invoke(next, invocation); } }; } } return last; } ``` Dubbo的责任链就没有类似FilterChain这样的类吧Filter和调用Invoker结合起来,而是通过创建一个链表,调用的时候我们只知道第一个节点,每个节点包含了下一个调用的节点信息。 这里的虽然Invoker封装Filter没有显示的指定next,但是通过java匿名类和final的机制达到同样的效果。 ![](http://114.67.107.180/ynblog/upload/1605170411665.png) #### Mybatis中的Plugin Mybatis可以配置各种Plugin,无论是官方提供的还是自己定义的,Plugin和Filter类似,就在执行Sql语句的时候做一些操作。Mybatis的责任链则是通过动态代理的方式,使用Plugin代理实际的Executor类。(这里实际还使用了组合模式,因为Plugin可以嵌套代理),核心代码如下: ``` public class Plugin implements InvocationHandler{ private Object target; private Interceptor interceptor; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (满足代理条件) { return interceptor.intercept(new Invocation(target, method, args)); } return method.invoke(target, args); } //对传入的对象进行代理,可能是实际的Executor类,也可能是Plugin代理类 public static Object wrap(Object target, Interceptor interceptor) { Class> type = target.getClass(); Class>[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; } } ``` ![](http://114.67.107.180/ynblog/upload/1605170425534.png)