分析:
过滤器链的调用过程
A过滤器调用chain.doFilter此时会进入到下一个过滤器
B过滤器继续调用chain.doFilter会继续进入下一个过滤器
当所有过滤器都执行完成后,会进入目标方法。
既然chain.doFilter能进入下一个过滤器,那本质上就是方法的调用压栈和弹栈,一个方法的调用入口会执行完成所有的方法栈后才完成。
所以chain内肯定知道下一个filter是哪个,同时chain肯定保存了最终的目标执行对象。
基于以上分析,chain内部维护了一个过滤器集合,并知道下一个过滤器是哪个。
运行结果:
首先,任何编程语言在调用一个方法,都会层层调用多层方法栈。
A
B
C
D
E....
其实,责任链设计模式无非就是通过代码解耦,将复杂的逻辑线性化。将一个一个的调用串行化。
FilterChain将责任链的执行权交给每个过滤器,由过滤器决定是否执行下一个过滤器。
java
@Data
@Builder
public class HttpServletRequest {
private String method;
private String uri;
}
java
public class TargetController {
public void target() {
System.out.println("执行了最终的目标方法");
}
}
java
public interface Filter {
void doFilter(FilterChain filterChain, HttpServletRequest request) throws Exception;
}
java
public class AuthFilter implements Filter {
@Override
public void doFilter(FilterChain filterChain, HttpServletRequest request) throws Exception {
System.out.println("auth filter before");
filterChain.doFilter(request);
System.out.println("auth filter after");
}
}
java
public class LogFilter implements Filter{
@Override
public void doFilter(FilterChain filterChain, HttpServletRequest request) throws Exception {
System.out.println("log filter before ");
filterChain.doFilter(request);
System.out.println("log filter after ");
}
}
java
@Data
@Builder
public class FilterChain {
private Integer index;
private List<Filter> filters;
//执行最终目标方法的对象
private Object target;
//执行最终的目标方法
private Method method;
//执行最终目标方法的
private Object[] args;
public void doFilter(HttpServletRequest request) throws Exception {
//获取当前要执行的过滤器
if (index == null){
index = 0;
}
if (filters == null || filters.size() <= 0){
return;
}
if (index >= filters.size()){
//执行最终的目标方法
method.invoke(target,args);
return;
}
//获取过滤器
Filter filter = filters.get(index++);
filter.doFilter(this,request);
}
}
java
public class Test {
public static void main(String[] args) throws Exception {
FilterChain filterChain = FilterChain.builder()
.filters(
Arrays.asList(new AuthFilter(), new LogFilter())
)
.index(0)
.target(new TargetController())
.method(TargetController.class.getMethod("target"))
.args(null)
.build();
filterChain.doFilter(new HttpServletRequest("GET","/test"));
}
}