简单过滤链的实现思路
模仿SpringMVVC的FilterChain方式,使用过滤链的思路实现功能逻辑。
概述
有点类似springMVC中的filter,多个filter形成一条过滤链,依次处理一个请求,并传给下一个filter,最后才分发到各个controller进行业务处理。
现在想实现的是这样一种功能,使用一个过滤链处理一个请求:
- 时间过滤器在请求开始时记录时间,结束后统计请求时间并打印;
- 日志过滤器在请求发送到服务器前打印请求的数据,数据从服务器返回后打印返回的数据;
- 其他…
思路
首先写好fiter和filterChain的接口类:
1
2
3
4
5
6
7
8
9
10
11public interface Filter {
void init();
void doFilter(FilterChain chain) throws TException;
void destory();
}
public interface FilterChain {
void doFilter() throws TException;
Object getAttribute(String name);
void setAttribute(String name, Object value);
}实现一个过滤链类,implemts FilterChain:
- 首先定义一个静态的Filter列表,在向这个列表添加filter之后,所有请求共用这个列表,被filters列表中的filter依次处理;
- 定义一个变量
Map<String, Object>attributes = new HashMap<>()
,每个请求new一个FilterChain,以此保存每个请求各自的一些参数,并将该FilterChain作为参数传递给Filter的doFilter方法,这样,Filter处理不同的请求时,就能从attributes中拿到每个请求不同的参数; - 实现doFilter方法: 注意这里index不是静态的,所以对于每个请求来说,它都是从第一个开始依次拿到filters列表中的Filter,并用这个Filter处理这个过滤链(通过this/fiterChain将attributes传递给每一个Filter),如果静态的filter拿完了,就拿最后一个-每个请求自己定义的-Filter,这个过滤链就算完成了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25protected int index = -1;
protected Filter lastFilter;
@Override
public void doFilter() throws TException {
next().doFilter(this);
}
public Filter next() {
Filter filter = nextFilter();
return filter == null ? lastFilter : filter;
}
protected Filter nextFilter() {
if (++index >= filters.size())
return null;
else {
Filter filter = null;
try {
filter = filters.get(index);
} catch (IndexOutOfBoundsException e) {
}
return filter;
}
}
实现共用的Filter,以计时过滤器TimeFilter为例:
1
2
3
4
5
6
7
8
9
10@Override
public void doFilter(FilterChain chain) throws TException {
final long startTime = System.currentTimeMillis();
try {
chain.doFilter();
} finally {
LOGGER.info("耗时:{}ms", System.currentTimeMillis() - startTime);
}
}当请求调用过滤链filterChain.doFilter()方法时,该请求线程从filters列表中拿到第一个Filter(即此时TimeFilter),记录下当前时间,然后在try中使用该filterChain继续拿下一个Filter并处理请求…一直传递下去,直到最后一个Filter(即请求自定义的Filter),在该Filter中,不再继续向下传递,而是完成实际想要完成的操作。后面的操作结束后,终于轮到时间过滤器TimeFilter中的finally块,记录整个操作的时间。
实现自定义的业务Filter和方法:
不同的请求有不同的业务需求,因此,先实现一个具体的业务方法,并将这个方法作为参数放入filterChain中的attributes中。每个过滤链中的最后一个Filter,就负责从filter中拿到这个方法,使用这个方法完成业务逻辑,至于方法需要的参数,已经保存在attributes中了。
1
2
3
4
5
6
7
8
9
10
11
12final StubFilterChain stubFilterChain = new StubFilterChain();
stubFilterChain.setLastFilter(new SendMessageFilter());
stubFilterChain.setAttribute("request", request);
stubFilterChain.setAttribute("sendMessage", (SendMessageFilter.SendMessageAction)(chain) -> {
RESP resp = {...};
chain.setAttribute("response", resp);
});
stubFilterChain.doFilter();
return (RESP) stubFilterChain.getAttribute("response");SendMessageFilter:
1
2
3
4
5
6
7
8
9
10
11
12public class SendMessageFilter implements Filter {
public interface SendMessageAction {
void doAction(FilterChain chain) throws TException;
}
@Override
public void doFilter(FilterChain chain) throws TException {
SendMessageAction action = (SendMessageAction) chain.getAttribute("sendMessage");
action.doAction(chain);
}
......可以看到,SendMessageFilter做的事情,就是从FilterChain实例的attributes中拿到实现的SendMessageAction的实例,并调用这个Action实例中的doAction完成业务逻辑。这个Action实例就是上面new并set进去的,在Action方法中,经过一系列操作,得到了结果response,并将结果放入attributes,这条过滤链处理完后,即调用完filterChain.doFilter()后,就可以通过filterChain.getAttribute(“response”)将action放进去的结果拿出来了。