开发一个框架或者中间件,基本上都会涉及到过滤器,在设计模式中又被称为责任链模式。本文就主要讲过滤器设计,分为以下内容,其中过滤器简单demo是重点,这会是在写框架中的一种可行性方案。
概述
- 过滤器是什么。
- 过滤器设计的概念。
- 过滤器和拦截器。
- 设计模式中的责任链。
- dubbo中的过滤器设计和表述其方案的demo。
- servlet,spring,mybatis中的过滤。
- 过滤器简单demo
过滤器是什么
我们在做开发的时候,经常是请求或者调用进进出出,有时候需要对请求数据做一些处理,就要用到过滤器,1个过滤器可以和多个请求(调用)入口绑定,对数据进行修改验证等。比如说,请求接口是否有权限。对参数进行统一的加减信息。
过滤器设计的概念。
- Filter接口,一般给具体的过滤器实现者去实现。Filter提供过滤方法,方法参数会有2者,1是内部的调用者自身,2是参数。比如下面的代码
public interface Filter {//dubbo中的Filter,invoker表示内部调用者,invocation表示过滤参数
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
}
public interface Filter {//servlet中的Filter,FilterChain 表示内部调用者,request和response表示过滤参数
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
}
- FilterChain
调用链路,FilterChain只有1个,但是内部会维护很多Filter ,FilterChain作为链路也会往下传递。dubbo中Invoker起了类似的概念。 - 请求参数
请求参数包括请求和响应参数,该参数也是只有1个,从调用前往后不断传递。
过滤器和拦截器。
过滤器Filter如上述,拦截器Interceptor一般功能也是类似的,在spring中Interceptor用boolean的返回值去表述后面是否继续执行,而在mybatis中Interceptor也仅仅是对参数的修改。2者都可以通过抛出异常阻止后面继续执行。
设计模式中的责任链。(Chain of Responsibility)
责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
我在自己的云笔记里记录了一些相关资料。简单的:责任链有两点,1责任,2链路
角色有,Handler抽象处理者,ConcreteHandle具体处理者
public abstract class Handler {
//持有后继的责任对象
protected Handler successor;
}
public class ConcreteHandler extends Handler {
public void handleRequest() {
//判断是否有后继的责任对象 如果有,就转发请求给后继的责任对象 如果没有,则处理请求
if (getSuccessor() != null) {
System.out.println("放过请求");
getSuccessor().handleRequest();
} else {
System.out.println("处理请求");
}
}
}
dubbo中的过滤器设计和表述其方案的demo。
dubbo中的过滤器只要是在ProtocolFilterWrapper的buildInvokerChain方法,其中Invoker,Invocation和Filter是其核心类。下面用简单的代码去表述dubbo的过滤器。
//为了代码简短,没有写引用路径,包路径假设默认是com.demo.filter.dubbo,代码如下,代码可以直接复制到IDE中
import java.util.Arrays;
import java.util.List;
interface Filter {
Result invoke(Invoker invoker, Invocation invocation);
}
class Invocation {
private String name;
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
}
class BuildFilter {
public static <T> Invoker buildInvokerChain(final Invoker invoker, List<Filter> filters) {
Invoker last = invoker;
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker next = last;
last = new Invoker() {
public Result invoke(Invocation invocation) {
return filter.invoke(next, invocation);
}
};
}
}
return last;
}
}
interface Invoker {
Result invoke(Invocation invocation);
}
class Result {
private String name;
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
}
class FilterA implements Filter {
public Result invoke(Invoker invoker, Invocation invocation) {
invocation.setName(invocation.getName() + "A做了修饰");
return invoker.invoke(invocation);
}
}
class FilterB implements Filter {
public Result invoke(Invoker invoker, Invocation invocation) {
invocation.setName(invocation.getName() + "B做了修饰");
return invoker.invoke(invocation);
}
}
class InvokerImpl implements Invoker {
public Result invoke(Invocation invocation) {
Result result = new Result();
result.setName(invocation.getName());
return result;
}
}
public class Main {
static void main(String[] args) {
Invoker invoker = new InvokerImpl();
Invoker invoker2 = BuildFilter.buildInvokerChain(invoker, Arrays.asList(new FilterA(), new FilterB()));
Invocation invocation = new Invocation();
invocation.setName("我是请求参数");
Result result = invoker2.invoke(invocation);
System.out.println(result.getName());
}
}
servlet,spring,mybatis中的过滤。
servlet和spring的过滤器都指的是javax.servlet.Filter。实现可以看tomcat的代码ApplicationFilterChain 。
该方式比较简单,在ApplicationFilterChain 中维护了一个数组ApplicationFilterConfig[] filters。然后遍历filters拿到配置的filter,然后调用MyFilter.doFilter(Request,Response,FilterChain)方法。
这里的调用是这样的
filter[pos++].doFilter(request, response, this);//ApplicationFilterChain 代码中,这里的filter得到的是myFilter。
filterChain.doFilter(request, response);//myFilter代码中。
//这里的this指的就是filterChain,也是ApplicationFilterChain 。
//这里看似地柜了,实际是通过pos++,每次都获取到下一个Filter。
//这里把filterChain用this在传递,实际上可以控制调用链是否往下继续进行。如果没有这个参数,则只能对参数修改,无法控制流程。
//在ApplicationFilterChain 这个类中的internalDoFilter方法会先执行过滤器,当过滤器的pos到头时,然后去执行servlet。
过滤器简单demo
public class Main {
static void main(String[] args) {
FilterChain filterChain = new FilterChain();
FilterChain.addFilter(new Filter() {
Response doFilter(Request request, FilterChain filterChain) {
request.setName(request.getName() + "aaa");
return filterChain.doFilter(request);
}
});
FilterChain.addFilter(new Filter() {
Response doFilter(Request request, FilterChain filterChain) {
request.setName(request.getName() + "bbb");
return filterChain.doFilter(request);
}
});
filterChain.setWorker(new Worker() {
Response doWork(Request request) {
String name = request.getName();
Response response = new Response();
response.setName(name + "返回");
return response;
}
});
Response response = filterChain.doFilter(new Request());
System.out.println(response);
}
}
interface Filter { Response doFilter(Request request, FilterChain filterChain);}
class FilterChain {
private static List<Filter> filters = new ArrayList<>();
static void addFilter(Filter filter) {
filters.add(filter);
}
private int pos = 0;
private Worker worker;
Worker getWorker() {
return worker;
}
void setWorker(Worker worker) {
this.worker = worker;
}
Response doFilter(Request request) {
if (pos < filters.size()) {
Filter filter = filters.get(pos++);
return filter.doFilter(request, this);
}
return worker.doWork(request);
}
}
class Request {
private String name = "123";
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
}
class Response {
private String name;
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
}
interface Worker {
Response doWork(Request request);
}
网友评论