一、模式解析
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
责任链模式的要点主要是:
1、有多个对象共同对一个任务进行处理。
2、这些对象使用链式存储结构,形成一个链,每个对象知道自己的下一个对象。
3、一个对象对任务进行处理,可以添加一些操作后将对象传递个下一个任务。也可以在此对象上结束任务的处理,并结束任务。
3、客户端负责组装链式结构,但是客户端不需要关心最终是谁来处理了任务。
二、模式代码
1、创建处理器接口
package chain.patten;
/**
* 责任链接口
* @author zjl
* @time 2016-2-11
*
*/
public abstract class Handler {
//下一级责任链
public Handler handler;
//设置下一级责任链
public void setSuccessor(Handler handler){
this.handler=handler;
}
public abstract void request(int request);
}
2、创建处理器对象1
package chain.patten; public class ConcreteHandler1 extends Handler {
@Override
public void request(int request) {
if(request<10){
System.out.println("我是handler1,我处理了请求:"+request);
}else {
this.handler.request(request);
}
}
}
3、创建处理器对象2
package chain.patten; public class ConcreteHandler2 extends Handler {
@Override
public void request(int request) {
if(request>10){
System.out.println("我是handler2,我处理了请求:"+request);
}else {
System.out.println("请求"+request+"没人能处理");
}
}
}
4、创建客户端
package chain.patten; public class Client {
public static void main(String[] args) {
//创建处理器
Handler handler1=new ConcreteHandler1();
Handler handler2=new ConcreteHandler2();
//客户端创建处理器的关联,形成链
handler1.setSuccessor(handler2);
//创建任务,此处为一些数字,不同大小,处理器处理结果不同
int[] requests={4,10,59,2,16};
//调用处理器处理
for(int request:requests){
handler1.request(request);
}
}
}
5、执行结果
我是handler1,我处理了请求:4
请求10没人能处理
我是handler2,我处理了请求:59
我是handler1,我处理了请求:2
我是handler2,我处理了请求:16
三、应用场景
在工作中,尤其是java web开发中,有两个地方明显使用责任链模式,一个是filter,一个是listener,filter的自定义在web开发中可以对web请求做各种处理和过滤,包括:对请求和相应的字符集处理、对跨站脚本攻击的过滤、获取客户端真实ip地址、获取客户证书、防止盗链等等,在此处,简单模拟责任链模式对请求的处理。
四、场景代码
1、过滤器接口
package chain.example; public abstract class Filter {
//request 和response在真正的servlet中是对象,此处简化处理为string
public abstract void doFilter(String request,String response,FilterChain filterChain);
}
2、过滤器-处理字符集
package chain.example; public class EncodeFilter extends Filter { @Override
public void doFilter(String request, String response, FilterChain filterChain) {
System.out.println("对request做utf-8编码");
filterChain.doFilter(request, response);
System.out.println("对response做utf-8编码");
} }
3、过滤器-处理xss攻击
package chain.example; public class XssFilter extends Filter { @Override
public void doFilter(String request, String response, FilterChain filterChain) {
System.out.println("过滤request的xss内容");
filterChain.doFilter(request, response);
System.out.println("过滤response的xss内容");
} }
4、servlet接口,仅实现service接口
package chain.example; public interface Servlet {
public void service(String request,String response);
}
5、定义一个servlet实现
package chain.example; public class MainServlet implements Servlet { @Override
public void service(String request, String response) {
System.out.println(request);
//为response赋值
response="返回结果";
System.out.println(response);
} }
6、定义内部处理的filter链,链中保存真正filter的执行顺序,和servlet
package chain.example; import java.util.ArrayList;
import java.util.List; public class FilterChain {
private int cursor;
public List<Filter> filters=new ArrayList<Filter>();
public Servlet servlet;
public void setServlet(Servlet servlet){
this.servlet=servlet;
}
public void addFilter(Filter filter){
this.filters.add(filter);
} public void doFilter(String request,String response){
if(cursor<filters.size()){
filters.get(cursor++).doFilter(request, response,this);
}else {
servlet.service(request, response);
}
}
}
7、客户端代码
package chain.example; public class Client {
public static void main(String[] args) {
//定义filter
Filter encodeFilter=new EncodeFilter();
Filter xssFilter=new XssFilter();
FilterChain chain=new FilterChain();
chain.addFilter(encodeFilter);
chain.addFilter(xssFilter); //定义servlet
Servlet servlet=new MainServlet();
chain.setServlet(servlet);
chain.doFilter("发送请求", "");
}
}
8.、执行结果
对request做utf-8编码
过滤request的xss内容
发送请求
返回结果
过滤response的xss内容
对response做utf-8编码
五、实例说明
filter的责任链实现与责任链模式的标准代码有着一定的差距,它具有如下特点:
1、责任链的实现并不是链式结构,而是以一个FilterChain保存了所有责任链的引用,通过FilterChain的doFilter方法依次调用filter进行执行;
2、filter中同时也保存了FilterChain的引用,形成了一个双向引用;
3、FilterChain作为web容器的功能,由系统默认提供,我们无需关注其实现原理(注:代码中仅为可能实现的方式)。他依次将web.xml中的filter按照文件排放顺序进行调用执行。
由此我们思考,责任链模式的实现应该有多种形式,可以为责任链之间的互相链式引用,也可以为第三方集合中的顺序执行方式,在我所接触最广泛的系统中,对责任链进行如下使用:在执行真正交易时候,根据模板选择责任链,在配置文件中定义了一些列的Command,由chain方法将其转化为一个list的责任链,然后使用迭代器依次执行,对系统的传递请求进行一些列操作,格式为:
<chain id="chainForRoleControlDV">
<commands>
<ref>RuleBasedDynamicViewCommand</ref>
<ref>roleControlCommand</ref>
<ref>validationCommand</ref>
<ref>ruleCommand</ref>
<ref>delegateCommand</ref>
<ref>${chain.monitor}</ref>
</commands>
</chain>
此种可以对请求进行登录控制,字段校验,权限控制,监控信息发送,验证码校验等一些列操作。这样只需要定义几个责任链可以完成对所有交易的区分控制。