快速学习#
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
责任链模式(Chain of Responsibility)是一种处理请求的模式,它让多个处理器都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌─────────┐
│ Request │
└─────────┘
│
┌ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ┐
▼
│ ┌─────────────┐ │
│ ProcessorA │
│ └─────────────┘ │
│
│ ▼ │
┌─────────────┐
│ │ ProcessorB │ │
└─────────────┘
│ │ │
▼
│ ┌─────────────┐ │
│ ProcessorC │
│ └─────────────┘ │
│
└ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ┘
│
▼
copy
在实际场景中,财务审批就是一个责任链模式。假设某个员工需要报销一笔费用,审核者可以分为:
Manager:只能审核1000元以下的报销;
Director:只能审核10000元以下的报销;
CEO:可以审核任意额度。
用责任链模式设计此报销流程时,每个审核者只关心自己责任范围内的请求,并且处理它。对于超出自己责任范围的,扔给下一个审核者处理,这样,将来继续添加审核者的时候,不用改动现有逻辑。
我们来看看如何实现责任链模式。
首先,我们要抽象出请求对象,它将在责任链上传递:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Request {
private String name;
private BigDecimal amount;
public Request(String name, BigDecimal amount) {
this .name = name;
this .amount = amount;
}
public String getName() {
return name;
}
public BigDecimal getAmount() {
return amount;
}
}
copy
其次,我们要抽象出处理器:
1
2
3
4
5
6
public interface Handler {
// 返回Boolean.TRUE = 成功
// 返回Boolean.FALSE = 拒绝
// 返回null = 交下一个处理
Boolean process(Request request);
}
copy
并且做好约定:如果返回Boolean.TRUE
,表示处理成功,如果返回Boolean.FALSE
,表示处理失败(请求被拒绝),如果返回null
,则交由下一个Handler
处理。
然后,依次编写ManagerHandler、DirectorHandler和CEOHandler。以ManagerHandler为例:
1
2
3
4
5
6
7
8
9
10
public class ManagerHandler implements Handler {
public Boolean process(Request request) {
// 如果超过1000元,处理不了,交下一个处理:
if (request.getAmount ().compareTo (BigDecimal.valueOf (1000)) > 0) {
return null ;
}
// 对Bob有偏见:
return !request.getName ().equalsIgnoreCase ("bob" );
}
}
copy
有了不同的Handler
后,我们还要把这些Handler
组合起来,变成一个链,并通过一个统一入口处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class HandlerChain {
// 持有所有Handler:
private List<Handler> handlers = new ArrayList<>();
public void addHandler(Handler handler) {
this .handlers .add (handler);
}
public boolean process(Request request) {
// 依次调用每个Handler:
for (Handler handler : handlers) {
Boolean r = handler.process (request);
if (r != null ) {
// 如果返回TRUE或FALSE,处理结束:
System.out .println (request + " " + (r ? "Approved by " : "Denied by " ) + handler.getClass ().getSimpleName ());
return r;
}
}
throw new RuntimeException("Could not handle request: " + request);
}
}
copy
现在,我们就可以在客户端组装出责任链,然后用责任链来处理请求:
1
2
3
4
5
6
7
8
9
10
// 构造责任链:
HandlerChain chain = new HandlerChain();
chain.addHandler (new ManagerHandler());
chain.addHandler (new DirectorHandler());
chain.addHandler (new CEOHandler());
// 处理请求:
chain.process (new Request("Bob" , new BigDecimal("123.45" )));
chain.process (new Request("Alice" , new BigDecimal("1234.56" )));
chain.process (new Request("Bill" , new BigDecimal("12345.67" )));
chain.process (new Request("John" , new BigDecimal("123456.78" )));
copy
责任链模式本身很容易理解,需要注意的是,Handler
添加的顺序很重要,如果顺序不对,处理的结果可能就不是符合要求的。
此外,责任链模式有很多变种。有些责任链的实现方式是通过某个Handler
手动调用下一个Handler
来传递Request
,例如:
1
2
3
4
5
6
7
8
9
10
11
public class AHandler implements Handler {
private Handler next;
public void process(Request request) {
if (!canProcess(request)) {
// 手动交给下一个Handler处理:
next.process (request);
} else {
...
}
}
}
copy
还有一些责任链模式,每个Handler
都有机会处理Request
,通常这种责任链被称为拦截器(Interceptor)或者过滤器(Filter),它的目的不是找到某个Handler
处理掉Request
,而是每个Handler
都做一些工作,比如:
例如,JavaEE的Servlet规范定义的Filter
就是一种责任链模式,它不但允许每个Filter
都有机会处理请求,还允许每个Filter
决定是否将请求“放行”给下一个Filter
:
1
2
3
4
5
6
7
8
9
10
11
12
public class AuditFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
log(req);
if (check(req)) {
// 放行:
chain.doFilter (req, resp);
} else {
// 拒绝:
sendError(resp);
}
}
}
copy
这种模式不但允许一个Filter
自行决定处理ServletRequest
和ServletResponse
,还可以“伪造”ServletRequest
和ServletResponse
以便让下一个Filter
处理,能实现非常复杂的功能。
类型:行为型
责任链模式是一种对象的行为模式。
在责任链模式里,很多对象由每一个对象对其下家的的引用而连起来形成一条链。
请求在这条链上传递,直到链上的某一个对象决定处理这个请求。
发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,
这使得系统可以在不影响客户端的情况下,动态的重新组织和分配责任。
意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
何时使用:在处理消息的时,需要过滤很多道程序。
如何解决:拦截的类都实现统一接口。
关键代码:Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
应用实例:
红楼梦中的"击鼓传花"。
JS 中的事件冒泡。
JAVA WEB 中 Apache Tomcat 对 Encoding 的处理。
jsp servlet 的 Filter。
优点:
降低耦合度。它将请求的发送者和接收者解耦。
简化了对象。使得对象不需要知道链的结构。
增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
增加新的请求处理类很方便。
缺点:
不能保证请求一定被接收。
系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
可能不容易观察运行时的特征,有碍于除错。
使用场景:
有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
可动态指定一组对象处理请求。
击鼓传花#
击鼓传花是一种热闹而又紧张的饮酒游戏。在酒宴上宾客依次坐定位置,由一人击鼓,击鼓的地方与传花的地方是分开的,以示公正。开始击鼓时,花束就开始依次传递,鼓声一落,如果花束在某人手中,则该人就得饮酒。比如说,贾母、贾赦、贾政、贾宝玉和贾环是五个参加击鼓传花游戏的传花者,他们组成一个环链。击鼓者将花传给贾母,开始传花游戏。花由贾母传给贾赦,由贾赦传给贾政,由贾政传给贾宝玉,又贾宝玉传给贾环,由贾环传回给贾母,如此往复,如下图所示。当鼓声停止时,手中有花的人就得执行酒令。
击鼓传花便是责任链模式的应用。
责任链可以是一条直线,一个环链或者一个树状结构的一部分。
责任链模式的结构#
下面使用了一个责任链模式的最简单的实现。
责任链模式涉及到的角色如下所示:
抽象处理者(Handler):一个处理请求的接口。
如果需要,接口可以定义出一个方法以设定和返回对下家的引用。
这个角色通常由一个JAVA抽象类或者JAVA接口实现。
上图中的Handler类的聚合关系给出了具体子类对下家的引用。
抽象方法handlerReuqest()规范了类处理请求的操作。
具体处理者(ConcreteHandler):
具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。
抽象处理者:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class Handler {
//持有后继的责任对象
protected Handler successor;
/**
* 示意处理请求的方法,虽然这个示意方法是没有传入参数的,
* 但实际是可以传入参数的,根据具体需求来选择是否传递参数
*/
public abstract void handlerRequest();
public Handler getSuccessor() {
return successor;
}
public void setSuccessor(Handler successor) {
this .successor = successor;
}
}
copy
具体处理者:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ConcreteHandler extends Handler{
/**
* 处理方法,调用此方法处理请求
*/
@Override
public void handlerRequest() {
/**
* 判断是否有后继的责任对象
* 如果有,就转发请求有给后继的责任对象
* 如果没有,则处理请求
* */
if (getSuccessor() != null ) {
System.out .println ("放过请求" );
getSuccessor().handlerRequest ();
} else {
System.out .println ("处理请求" );
}
}
}
copy
客户端:
1
2
3
4
5
6
7
8
9
10
11
12
public class Client {
public static void main(String[] args) {
//组装责任链
Handler h1 = new ConcreteHandler();
Handler h2 = new ConcreteHandler();
h1.setSuccessor (h2);
//提交请求
h1.handlerRequest ();
}
}
copy
可以看出,客户端创建了两个处理者对象,并指定第一个处理者对象的下家是第二个处理者对象,而第二个处理者对象没有下家。然后客户端将请求传递给第一个处理者对象。
由于本实例的传递逻辑非常简单:
只要有下家,就传递给下家处理;
如果没有下家,就自行处理。
因此,第一个处理者对象接到请求后,会将请求传递给第二个处理者对象。由于第二个处理者对象没有下家,于是自行处理请求。
活动时序图如下所示:
使用场景1(申请流程)#
场景:申请聚餐费用的管理。
申请聚餐费用的流程一般是:
由申请人先填写申请单,然后交给领导审批。
若批准通过,领导会通知申请人审批通过,然后申请人去财务领取费用。
若审批未通过,领导会通知申请人审批未通过,此事也就此作罢。
不同级别的领导,对于审批的额度是不一样的,比如,
项目经理只能审批500元以内的申请;
部门经理能审批1000元以内的申请;
而总经理可以审核任意额度的申请。
某人提出申请后,该请求会由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,但是提出申请的人并不知道最终会由谁来处理他的请求。
使用责任链模式来实现上述功能:
某人提出申请
该请求会在 项目经理->部门经理->总经理 这样一条领导处理链上进行传递
每个领导会根据自己的职责范围,来判断是处理请求还是把请求交给更高级别的领导,只要有领导处理了,传递就结束了。
需要把每位领导的处理独立出来,实现成单独的职责处理对象,然后为它们提供一个公共的、抽象的父职责对象,这样就可以在客户端来动态地组合职责链,实现不同的功能要求了。
抽象处理者角色类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class Handler {
//持有下一个处理请求的对象
protected Handler successor = null ;
//取值方法
public Handler getSuccessor() {
return successor;
}
//设置下一个处理请求的对象
public void setSuccessor(Handler successor) {
this .successor = successor;
}
/**
* 处理聚餐费用的申请
* @param user 申请人
* @param fee 申请的钱数
* @return 成功或失败的具体通知
*/
public abstract String handleFeeRequest(String user , double fee);
}
copy
具体处理者角色:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ProjectManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "" ;
//项目经理权限比较小,只能在500以内
if (fee < 500) {
//为了测试,简单点,只同意张三的请求
if ("张三" .equals (user)) {
str = "成功:项目经理同意【" + user + "】的聚餐费用,金额为" + fee + "元" ;
} else {
//其他人一律不同意
str = "失败:项目经理不同意【" + user + "】的聚餐费用,金额为" + fee + "元" ;
}
} else {
//超过500,继续传递给级别更高的人处理
if (getSuccessor() != null ) {
return getSuccessor().handleFeeRequest (user, fee);
}
}
return str;
}
}
copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class DeptManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "" ;
//部门经理的权限只能在1000以内
if (fee < 1000) {
//为了测试,简单点,只同意张三的请求
if ("张三" .equals (user)) {
str = "成功:部门经理同意【" + user + "】的聚餐费用,金额为" + fee + "元" ;
} else {
//其他人一律不同意
str = "失败:部门经理不同意【" + user + "】的聚餐费用,金额为" + fee + "元" ;
}
} else {
//超过1000,继续传递给级别更高的人处理
if (getSuccessor() != null ) {
return getSuccessor().handleFeeRequest (user, fee);
}
}
return str;
}
}
copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class GeneralManager extends Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "" ;
//总经理的权限很大,只要请求到了这里,他都可以处理
if (fee >= 1000) {
//为了测试,简单点,只同意张三的请求
if ("张三" .equals (user)) {
str = "成功:总经理同意【" + user + "】的聚餐费用,金额为" + fee + "元" ;
} else {
//其他人一律不同意
str = "失败:总经理不同意【" + user + "】的聚餐费用,金额为" + fee + "元" ;
}
} else {
//如果还有后继的处理对象,继续传递
if (getSuccessor() != null ) {
return getSuccessor().handleFeeRequest (user, fee);
}
}
return str;
}
}
copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Client {
public static void main(String[] args) {
//先要组装责任链
Handler h1 = new GeneralManager();
Handler h2 = new DeptManager();
Handler h3 = new ProjectManager();
h3.setSuccessor (h2);
h2.setSuccessor (h1);
//开始测试
String test1 = h3.handleFeeRequest ("张三" , 300);
System.out .println ("test1 = " + test1);
String test2 = h3.handleFeeRequest ("李四" , 300);
System.out .println ("test2 = " + test2);
System.out .println ("---------------------------------------" );
String test3 = h3.handleFeeRequest ("张三" , 700);
System.out .println ("test3 = " + test3);
String test4 = h3.handleFeeRequest ("李四" , 700);
System.out .println ("test4 = " + test4);
System.out .println ("---------------------------------------" );
String test5 = h3.handleFeeRequest ("张三" , 1500);
System.out .println ("test5 = " + test5);
String test6 = h3.handleFeeRequest ("李四" , 1500);
System.out .println ("test6 = " + test6);
}
}
copy
使用场景2(日志打印)#
创建抽象的记录器类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class AbstractLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
//责任链中的下一个元素
protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger){
this .nextLogger = nextLogger;
}
public void logMessage(int level, String message){
if (this .level <= level){
write(message);
}
if (nextLogger !=null ){
nextLogger.logMessage (level, message);
}
}
abstract protected void write(String message);
}
copy
三个扩展类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger(int level){
this .level = level;
}
@Override
protected void write(String message) {
System.out .println ("Standard Console::Logger: " + message);
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger(int level){
this .level = level;
}
@Override
protected void write(String message) {
System.out .println ("Error Console::Logger: " + message);
}
}
public class FileLogger extends AbstractLogger {
public FileLogger(int level){
this .level = level;
}
@Override
protected void write(String message) {
System.out .println ("File::Logger: " + message);
}
}
copy
创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ChainPatternDemo {
private static AbstractLogger getChainOfLoggers(){
AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR );
AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG );
AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO );
errorLogger.setNextLogger (fileLogger);
fileLogger.setNextLogger (consoleLogger);
return errorLogger;
}
public static void main(String[] args) {
AbstractLogger loggerChain = getChainOfLoggers();
loggerChain.logMessage (AbstractLogger.INFO , "This is an information." );
loggerChain.logMessage (AbstractLogger.DEBUG ,
"This is a debug level information." );
loggerChain.logMessage (AbstractLogger.ERROR ,
"This is an error information." );
}
}
copy
纯与不纯的责任链模式#
一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:要么承担责任,要么把责任推给下家。不允许出现某一个具体的处理者对象在承担了一部分责任后,又把责任向下传递的情况。
在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;
在一个不纯的责任链模式里面,一个请求最终可以不被任何接收端对象所接收。
纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。
有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的。但是在实际的系统里,纯的责任链很难找到。如果坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。
责任链模式在Tomcat中的应用#
众所周知Tomcat中的Filter就是使用了责任链模式,创建一个Filter除了要在web.xml文件中做相应配置外,还需要实现javax.servlet.Filter接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TestFilter implements Filter{
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter (request, response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
copy
其实在真正执行到TestFilter类之前,会经过很多Tomcat内部的类。
顺带提一下其实Tomcat的容器设置也是责任链模式,注意被红色方框所圈中的类,从Engine到Host再到Context一直到Wrapper都是通过一个链传递请求。
被绿色方框所圈中的地方有一个名为ApplicationFilterChain的类,ApplicationFilterChain类所扮演的就是抽象处理者角色,而具体处理者角色由各个Filter扮演。
第一个疑问是ApplicationFilterChain将所有的Filter存放在哪里?
答案是保存在ApplicationFilterChain类中的一个ApplicationFilterConfig对象的数组中。
1
2
3
4
/**
* Filters.
*/
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
copy
那ApplicationFilterConfig对象又是什么呢?
ApplicationFilterConfig是一个Filter容器。以下是ApplicationFilterConfig类的声明:
1
2
3
4
5
6
7
8
/**
* Implementation of a <code>javax.servlet.FilterConfig</code> useful in
* managing the filter instances instantiated when a web application
* is first started.
*
* @author Craig R. McClanahan
* @version $Id: ApplicationFilterConfig.java 1201569 2011-11-14 01:36:07Z kkolinko $
*/
copy
当一个web应用首次启动时ApplicationFilterConfig会自动实例化,它会从该web应用的web.xml文件中读取配置的Filter的信息,然后装进该容器。
刚刚看到在ApplicationFilterChain类中所创建的ApplicationFilterConfig数组长度为零,那它是在什么时候被重新赋值的呢?
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
是在调用ApplicationFilterChain类的addFilter()方法时。
1
2
3
4
/**
* The int which gives the current number of filters in the chain.
*/
private int n = 0;
copy
public static final int INCREMENT = 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void addFilter(ApplicationFilterConfig filterConfig) {
// Prevent the same filter being added multiple times
for (ApplicationFilterConfig filter:filters)
if (filter==filterConfig)
return ;
if (n == filters.length ) {
ApplicationFilterConfig[] newFilters =
new ApplicationFilterConfig[n + INCREMENT];
System.arraycopy (filters, 0, newFilters, 0, n);
filters = newFilters;
}
filters[n++] = filterConfig;
}
copy
变量n用来记录当前过滤器链里面拥有的过滤器数目,默认情况下n等于0,ApplicationFilterConfig对象数组的长度也等于0,所以当第一次调用addFilter()方法时,if (n == filters.length)的条件成立,
ApplicationFilterConfig数组长度被改变。之后filters[n++] = filterConfig;将变量filterConfig放入
ApplicationFilterConfig数组中并将当前过滤器链里面拥有的过滤器数目+1。
那ApplicationFilterChain的addFilter()方法又是在什么地方被调用的呢?
是在ApplicationFilterFactory类的createFilterChain()方法中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
public ApplicationFilterChain createFilterChain
(ServletRequest request, Wrapper wrapper, Servlet servlet) {
// get the dispatcher type
DispatcherType dispatcher = null ;
if (request.getAttribute (DISPATCHER_TYPE_ATTR) != null ) {
dispatcher = (DispatcherType) request.getAttribute (DISPATCHER_TYPE_ATTR);
}
String requestPath = null ;
Object attribute = request.getAttribute (DISPATCHER_REQUEST_PATH_ATTR);
if (attribute != null ){
requestPath = attribute.toString ();
}
// If there is no servlet to execute, return null
if (servlet == null )
return (null );
boolean comet = false ;
// Create and initialize a filter chain object
ApplicationFilterChain filterChain = null ;
if (request instanceof Request) {
Request req = (Request) request;
comet = req.isComet ();
if (Globals.IS_SECURITY_ENABLED ) {
// Security: Do not recycle
filterChain = new ApplicationFilterChain();
if (comet) {
req.setFilterChain (filterChain);
}
} else {
filterChain = (ApplicationFilterChain) req.getFilterChain ();
if (filterChain == null ) {
filterChain = new ApplicationFilterChain();
req.setFilterChain (filterChain);
}
}
} else {
// Request dispatcher in use
filterChain = new ApplicationFilterChain();
}
filterChain.setServlet (servlet);
filterChain.setSupport
(((StandardWrapper)wrapper).getInstanceSupport ());
// Acquire the filter mappings for this Context
StandardContext context = (StandardContext) wrapper.getParent ();
FilterMap filterMaps[] = context.findFilterMaps ();
// If there are no filter mappings, we are done
if ((filterMaps == null ) || (filterMaps.length == 0))
return (filterChain);
// Acquire the information we will need to match filter mappings
String servletName = wrapper.getName ();
// Add the relevant path-mapped filters to this filter chain
for (int i = 0; i < filterMaps.length ; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue ;
}
if (!matchFiltersURL(filterMaps[i], requestPath))
continue ;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig (filterMaps[i].getFilterName ());
if (filterConfig == null ) {
// FIXME - log configuration problem
continue ;
}
boolean isCometFilter = false ;
if (comet) {
try {
isCometFilter = filterConfig.getFilter () instanceof CometFilter;
} catch (Exception e) {
// Note: The try catch is there because getFilter has a lot of
// declared exceptions. However, the filter is allocated much
// earlier
Throwable t = ExceptionUtils.unwrapInvocationTargetException (e);
ExceptionUtils.handleThrowable (t);
}
if (isCometFilter) {
filterChain.addFilter (filterConfig);
}
} else {
filterChain.addFilter (filterConfig);
}
}
// Add filters that match on servlet name second
for (int i = 0; i < filterMaps.length ; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue ;
}
if (!matchFiltersServlet(filterMaps[i], servletName))
continue ;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig (filterMaps[i].getFilterName ());
if (filterConfig == null ) {
// FIXME - log configuration problem
continue ;
}
boolean isCometFilter = false ;
if (comet) {
try {
isCometFilter = filterConfig.getFilter () instanceof CometFilter;
} catch (Exception e) {
// Note: The try catch is there because getFilter has a lot of
// declared exceptions. However, the filter is allocated much
// earlier
}
if (isCometFilter) {
filterChain.addFilter (filterConfig);
}
} else {
filterChain.addFilter (filterConfig);
}
}
// Return the completed filter chain
return (filterChain);
}
copy
可以将如上代码分为两段,51行之前为第一段,51行之后为第二段。
第一段的主要目的是创建ApplicationFilterChain对象以及一些参数设置。
第二段的主要目的是从上下文中获取所有Filter信息,之后使用for循环遍历并调用
filterChain.addFilter(filterConfig);
将 filterConfig 放入 ApplicationFilterChain 对象的 ApplicationFilterConfig 数组中。
那ApplicationFilterFactory类的createFilterChain()方法又是在什么地方被调用的呢?
是在StandardWrapperValue类的invoke()方法中被调用的。
由于invoke()方法较长,所以将很多地方省略。
1
2
3
4
5
6
7
8
9
10
11
12
public final void invoke(Request request, Response response)
throws IOException, ServletException {
...省略中间代码
// Create the filter chain for this request
ApplicationFilterFactory factory =
ApplicationFilterFactory.getInstance ();
ApplicationFilterChain filterChain =
factory.createFilterChain (request, wrapper, servlet);
...省略中间代码
filterChain.doFilter (request.getRequest (), response.getResponse ());
...省略中间代码
}
copy
那正常的流程应该是这样的:
在StandardWrapperValue类的invoke()方法中调用ApplicationFilterChai类的createFilterChain()方法
–>
在ApplicationFilterChai类的createFilterChain()方法中调用ApplicationFilterChain类的addFilter()方法
–>
在ApplicationFilterChain类的addFilter()方法中给ApplicationFilterConfig数组赋值。
根据上面的代码可以看出StandardWrapperValue类的invoke()方法在执行完createFilterChain()方法后,会继续执行ApplicationFilterChain类的doFilter()方法,然后在doFilter()方法中会调用internalDoFilter()方法。
以下是internalDoFilter()方法的部分代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Call the next filter if there is one
if (pos < n) {
//拿到下一个Filter,将指针向下移动一位
//pos它来标识当前ApplicationFilterChain(当前过滤器链)执行到哪个过滤器
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = null ;
try {
//获取当前指向的Filter的实例
filter = filterConfig.getFilter ();
support.fireInstanceEvent (InstanceEvent.BEFORE_FILTER_EVENT ,
filter, request, response);
if (request.isAsyncSupported () && "false" .equalsIgnoreCase (
filterConfig.getFilterDef ().getAsyncSupported ())) {
request.setAttribute (Globals.ASYNC_SUPPORTED_ATTR ,
Boolean.FALSE );
}
if ( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal ();
Object[] args = new Object[]{req, res, this };
SecurityUtil.doAsPrivilege
("doFilter" , filter, classType, args, principal);
} else {
//调用Filter的doFilter()方法
filter.doFilter (request, response, this );
}
copy
这里的filter.doFilter(request, response, this);就是调用我们前面创建的TestFilter中的doFilter()方法。
而TestFilter中的doFilter()方法会继续调用chain.doFilter(request, response);方法,而这个chain其实就是ApplicationFilterChain,所以调用过程又回到了上面调用dofilter和调用internalDoFilter方法,这样执行直到里面的过滤器全部执行。
如果定义两个过滤器,则Debug结果如下:
tomcat中的责任链和上边说的责任链还是有区别的。
前面说的责任链,是靠每个链下面放置一个责任的参数,来定义责任的先后处理顺序。
tomcat的责任链则是通过数组来定义责任的先后顺序,tomcat责任链的模式更类似这样。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class filterChain{
private List<Filter> filters;
public void addFilter(Filter filter){
filters.add (filter);
}
public void do(HttpRequest request){
for (Filter filter:filters){
filter.do (request);
}
}
}
public class ConcreateFilter1 extends Filter{
public void do(HttpRequest request){
//do something
}
}
public class ConcreateFilter2 extends Filter{
public void do(HttpRequest request){
//do something
}
}
public class Client{
public void main(String[] args){
HttpRequest request = .....
FilterChain filterChain = new FilterChain();
filterChain.addFilter (new ConcreateFilter1());
filterChain.addFilter (new ConcreateFilter2());
filterChain.addFilter (new ConcreateFilter2());
filterChain.do (request);
}
}
copy
原文