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的效果。