Filter Pattern
1.什么是Filter Pattern?
Filter Pattern 也可以叫Intercepting Filter Pattern(拦截过滤器模式),这个范式可以让你在执行原有逻辑(核心逻辑)之前和之后额外执行一系列逻辑,像这样:
2.这个范式能给我们的代码带来什么好处?
Filter Pattern最广为人知的应用莫过于web应用中的servlet filter的,通过filter我们可以实现鉴权逻辑(哪些请求可以被执行下去,哪些不可以),access日志输出(对每个请求都输出日志参数)等。这些filter可以让系统在不修改核心业务逻辑的基础上,按照一定顺序添加切面功能,也就是Aspect Oriented Programming,实现功能的解耦合。
3.如何设计一个Filter Pattern?
首先任何设计模式都离不开应用场景,这里我们我们假定一个典型的http请求响应的逻辑:
public class HttpServlet implements Servlet{
@Override
public Response service(Request request){
Response response = new Response();
response.setData( "RESPONSE OF " + request.getData());
return response;
}
}
此时想在这个service逻辑上层添加print request的逻辑,以及modify request的逻辑,粗放的写法象这样:
public class HttpServlet implements Servlet{
@Override
public Response service(Request request){
System.out.println(request.getData());
request.setData("modify " + request.getData());
Response response = new Response();
response.setData( "RESPONSE OF " + request.getData());
return response;
}
}
这样当然能实现功能,但是代码的可维护性,可读性都会变得很差;于是把print 和 modify功能单独抽取出来like this;
public class HttpServlet implements Servlet{
/**
* 执行filterList,并执行service
* @param request
* @return
*/
public Response doFilter(Request request) {
List<SimpleFilter> simpleFilterList = buildFilterList();
for (SimpleFilter simpleFilter : simpleFilterList) {
simpleFilter.doBefore(request);
}
Response response = this.service(request);
for (SimpleFilter simpleFilter : simpleFilterList) {
simpleFilter.doAfter(response);
}
return response;
}
/**
* 构建Filter List
*/
private List<SimpleFilter> buildFilterList() {
List<SimpleFilter> filterList = new ArrayList<>();
SimpleFilter printFilter = new SimpleFilter() {
@Override
public void doBefore(Request request) {
System.out.println(request);
}
@Override
public void doAfter(Response response) {
//do noting
}
};
SimpleFilter modifyFilter = new SimpleFilter() {
@Override
public void doBefore(Request request) {
request.setData("modify " + request.getData());
}
@Override
public void doAfter(Response response) {
//do noting
}
};
filterList.add(printFilter);
filterList.add(modifyFilter);
return filterList;
}
@Override
public Response service(Request request){
Response response = new Response();
response.setData( "RESPONSE OF " + request.getData());
return response;
}
public interface SimpleFilter {
void doBefore(Request request);
void doAfter(Response response);
}
}
这里实现的逻辑和HandlerInterceptor
的思想很像,有兴趣的话可以看看org.springframework.web.servlet.HandlerInterceptor
相关的实现,都是在核心代码的前后循环调用interceptor
的函数;
但是这里有一个问题,当前版本的代码,SimpleFilter
的doBefore
方法无法控制流程是否往下走,无法实现类似流控,鉴权相关的功能;当然硬要在此基础上去改也能改出来,只不过不是很优雅,下面尝试另一个东西FilterChain
:
4.FilterChain
FilterChain
顾名思义,肯定包含一个Filter List
并且是用过addFilter
方法构建的, 有一个返回参数为Response
的doFilter
方法,看来是核心入口;看看它的实现类:
public interface FilterChain {
Response doFilter(Request request);
void addFilter(Filter filter);
}
public class ApplicationFilterChain implements FilterChain {
private List<Filter> filters;
//当前执行待执行filter的位置
private int position;
private Servlet servlet;
public ApplicationFilterChain() {
filters = new LinkedList<>();
position = 0;
servlet = new HttpServlet();
}
@Override
public Response doFilter(Request request) {
Filter currentFilter;
if (position < filters.size()){
currentFilter = filters.get(position);
position ++;
//顺序执行filter list
return currentFilter.doFilter(this, request);
}else {
//执行真正的service方法
return servlet.service(request);
}
}
@Override
public void addFilter(Filter filter) {
this.filters.add(filter);
}
}
ApplicationFilterChain 的代码总体符合猜想,但是多了servlet,position属性,position用来定位执行filter的执行位置,servlet放的是核心业务逻辑;
但是doFilter又是串起所有filter和servlet的呢?看一下新的Filter接口参数,以及实现类:
public interface Filter {
Response doFilter(FilterChain filterChain, Request request);
}
public class PrintFilter implements Filter {
@Override
public Response doFilter(FilterChain filterChain, Request request) {
//do my filter
System.out.println("realFilter.doFilter: " + request.getData());
return filterChain.doFilter(request);
}
}
public class ModifyFilter implements Filter {
@Override
public Response doFilter(FilterChain filterChain, Request request) {
request.setData("modified " + request.getData());
return filterChain.doFilter(request);
}
}
doFilter
签名是FilterChain
和Request
,这里的FilterChain
的用法是filterChain.doFilter(request)
,是用来串起所有filter list;
所以最后的代码执行时序是这样的(算是套了两个函数的递归调用)
filterChain.doFilter -> filter.doFilter -> filterChain.doFilter -> filter.doFilter -> filterChain.doFilter -> servlet.service
Main
方法如下:
public class Main {
public static void main(String[] args) {
FilterChain filterChain = buildFilterChain();
Response response = filterChain.doFilter(new Request("request"));
System.out.println(response.getData());
}
/**
* 构建filterChain
* @return
*/
private static FilterChain buildFilterChain() {
FilterChain filterChain = new ApplicationFilterChain();
//修改请求数据filter
Filter modifyDataFilter = new ModifyFilter();
//打印请求数据filter
PrintFilter printFilter = new PrintFilter();
filterChain.addFilter(modifyDataFilter);
filterChain.addFilter(printFilter);
return filterChain;
}
}
debug的线程栈如下图
在这个范式里面主要是FilterChain和Filter两个类的doFilter方法实现逻辑的串联,FilterChain控制每次执行第几个Filter,而Filter执行filter逻辑,并调用FilterChain去执行下一个Filter,如果这个Filter没有调用FilterChain而是直接return了,那么链路就会从当前Filter返回回去。
5.参考文献
posted on 2021-01-28 21:06 mindSucker 阅读(97) 评论(0) 编辑 收藏 举报