Filter与责任链模式
Filter
说起Filter大家应该都不陌生。Filter一般用于Servlet处理之前做一些前置的校验。如果校验通过,那么调用chain.doFilter(request, response)就可以让下一个filter继续执行逻辑。Filter是责任链模式的一种应用。接下来我们将探索、模拟Filter的实现逻辑。
责任链模式
责任链模式是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给连上的下一个处理者。
通过责任链对消息进行处理
对消息进行处理是一个非常简单的责任链模式的应用,直接看代码吧:
public class SimpleFilterChainMain {
public static void main(String[] args) {
//定义一个简单的消息对象
Msg msg = new Msg();
//消息内容
msg.setContent("hello,<script>alert(\"I am an alert box!!\")</script> world! ${jndi:rim:/xxx} ");
//定义一个过滤器链filterChain1
FilterChain filterChain1 = new FilterChain();
//为filterChain1中添加一个HTML标签的过滤器
filterChain1.add(new HTMLFilter());
//定义另一个过滤器链filterChain2
FilterChain filterChain2 = new FilterChain();
//为filterChain2添加一个敏感词的过滤器
filterChain2.add(new SensitiveFilter());
//将filterChain2本身也作为一个过滤器添加到filterChain1中
filterChain1.add(filterChain2);
//使用filterChain1对消息进行过滤
filterChain1.doFilter(msg);
//输出一下过滤之后的结果
System.out.println(msg.getContent());
}
/**
* 过滤器接口
*/
private interface Filter {
/**
* 过滤msg
* @param msg
*/
void doFilter(Msg msg);
}
/**
* 消息对象
*/
private static class Msg {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
/**
* HTML标签的过滤器
*/
private static class HTMLFilter implements Filter {
@Override
public void doFilter(Msg msg) {
String content = msg.getContent();
content = content.replace('<', '[');
content = content.replace('>', ']');
msg.setContent(content);
}
}
/**
* 敏感词的过滤器
*/
private static class SensitiveFilter implements Filter {
@Override
public void doFilter(Msg msg) {
String content = msg.getContent();
content = content.replaceAll("\\$\\{jndi:", "***");
msg.setContent(content);
}
}
/**
* 过滤器链,同时也实现了过滤器接口
*/
private static class FilterChain implements Filter {
List<Filter> filters = new ArrayList<>();
/**
* 向链中添加一个过滤器
*/
public void add(Filter filter) {
filters.add(filter);
}
@Override
public void doFilter(Msg msg) {
for (Filter filter : filters) {
filter.doFilter(msg);
}
}
}
}
反思与思考
以前我对责任链的理解仅仅只是到了Filter这一层,我认为只要有了一个List<Filter> filters 就算是责任链的体现了。所以所谓的“链”在我这里只是一个list而已。而在上面的例子中,我的责任链已经是一个FilterChain对象了。这个从list到对象的过程就体现了封装,封装是为了更好的变化。封装之后我的FilterChain还实现了Filter接口。这样做的好处是,链中每个过滤器既可以是独立的过滤器,比如HTMLFilter,也可以是另一个过滤器链,比如filterChain2。链与链就这么连上了。
Servlet中的Filter
我们先看看Servlet中的Filter是什么样的效果。
首先,我定义了一个Controller和3个Filter

在具体的Filter中其实什么也没有做,只是打印了两句话

接下来我们看下效果

也就是说先Filter1先处理Request,然后交给Filter2处理,最后交给Filter3处理,当Servlet处理完请求之后,再按照Filter321的顺序处理Response,就像下面的图这样。

模拟Servlet中Filter的处理模式
Servlet中的Filter之所以能够实现这么神奇的功能,核心原因在于Servlet的Filter有三个参数,Request、Response和FilterChain。
demo
接下来我们用demo演示一下:
/** * 尝试模拟一下servlet的filter调用过程 * @author skyline */ public class ServletFilterMain { public static void main(String[] args) { FilterChain filterChain = new MyFilterChain(); filterChain.addFilter(new Filter1()); filterChain.addFilter(new Filter2()); filterChain.addFilter(new Filter3()); filterChain.doFilter(new Request(), new Response()); } /** * 自定义过滤器 */ private interface Filter { /** * 执行过滤的逻辑 * @param request * @param response */ void doFilter(Request request, Response response, FilterChain filterChain); } /** * 过滤器链 */ private interface FilterChain { void doFilter(Request request, Response response); /** * 添加过滤器 * @param filter */ void addFilter(Filter filter); } private static class Filter1 implements Filter { private static final Logger logger = LoggerFactory.getLogger(Filter1.class); @Override public void doFilter(Request request, Response response, FilterChain filterChain) { logger.info("before filterChain.doFilter"); filterChain.doFilter(request, response); logger.info("after filterChain.doFilter"); } } private static class Filter2 implements Filter { private static final Logger logger = LoggerFactory.getLogger(Filter2.class); @Override public void doFilter(Request request, Response response, FilterChain filterChain) { logger.info("before filterChain.doFilter"); filterChain.doFilter(request, response); logger.info("after filterChain.doFilter"); } } private static class Filter3 implements Filter { private static final Logger logger = LoggerFactory.getLogger(Filter3.class); @Override public void doFilter(Request request, Response response, FilterChain filterChain) { logger.info("before filterChain.doFilter"); filterChain.doFilter(request, response); logger.info("after filterChain.doFilter"); } } /** * 模拟请求 */ private static class Request {} /** * 模拟响应 */ private static class Response {} private static class MyFilterChain implements FilterChain { private final List<Filter> filters; private int index; private MyFilterChain() { filters = new ArrayList<>(); index = -1; } @Override public void doFilter(Request request, Response response) { //这里再次体现了封装的必要性,因为如果单纯的遍历filters就无法实现我们想要的效果 int size = filters.size(); //每次doFilter时索引+1 index++; if (index < size) { //从filters中取出index位置的Filter,调用并调用doFilter filters.get(index).doFilter(request, response, this); } } @Override public void addFilter(Filter filter) { filters.add(filter); } } }
效果
先看下效果:

确实实现了123321的效果。
浙公网安备 33010602011771号