# Interceptor **Repository Path**: coder_chenjun/Interceptor ## Basic Information - **Project Name**: Interceptor - **Description**: 拦截器与过滤器的模拟实现 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-11-08 - **Last Updated**: 2021-11-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [TOC] # 1. 代码查看说明 本项目主要是对Struts2 的拦截器(与Filter的实现原理相同)以及Spring Mvc的拦截器的核心实现原理的一个实现,看懂此项目的代码,应该就可以看懂Struts 2拦截器与Spring Mvc拦截器的实现源码。当然,本项目会进行适当的简化 查看项目代码的顺序: - foundamental包或者interceptorimpl2包 - foundamental包下按version1->version2->version3的顺序查看 - interceptorfilterdemo包 # 2. 递归 要想理解Java Web中过滤器(Filter)的实现(其实现在Tomcat的源码中可以看到)或者Struts2的拦截器的实现,需要对递归有好的理解,在项目中你按照下面包的顺序查看来理解递归。 1. foundamental.version1 2. foundamental.version2 3. foundamental.version3 ## 2.1 version1(固定次数) 在包version1中,核心需要理解的就是下面的代码,其它都是用来辅助理解下面的代码的 ```java public class A { private int j = 0; public void am3(){ j++; System.out.println("method two in a " + j); if(j>=5) return ; //最大次数 new B().bm3(this); } } ``` ```java public class B { public void bm1(){ System.out.println("method one in b"); } public void bm3(A a){ System.out.println("method 2 in b"); a.am3(); //这里又调回a对象的am3方法 } } ``` ```java public class Main { public static void main(String[] args) { A a = new A(); a.am3(); } } ``` 由于是同一个A的实例,不断递增j的值时,会导致程序正确执行完毕,而不会导致堆栈溢出的错误。 ## 2.2 version2 次数可调整 这一个版本,做到递归调用次数可以通过list集合里面存放的对象数量来控制次数的目的 ```java public class A { List bList = new ArrayList<>(); public A(){ bList.add(new B(1)); bList.add(new B(2)); bList.add(new B(3)); bList.add(new B(4)); } private int i = -1; public void am1(){ i++; if(i>= bList.size()) return; System.out.println("method 1 in a----" + i); B b = bList.get(i); b.bm1(this); } } ``` ```java public class B { private int id; public B(int id) { this.id = id; } public void bm1(A a){ System.out.println("method 1 in B*****" + id); a.am1(); } } ``` ```java public class Main { public static void main(String[] args) { A a = new A(); a.am1(); } } ``` ## 2.3 version3 拦截器模拟实现 在这个版本中B相当于拦截器,C类相当于真正的处理者,而类A是管理整个拦截器与处理者的类型。 类比于Filter,那么B就是Filter,C就是某个Servlet,A就是FilterChain > 此时此刻,已经做到了之前、之后执行以及栈形式的执行结果。 ```java public class A { private C c = new C(); List bList = new ArrayList<>(); public A(){ bList.add(new B(1)); bList.add(new B(2)); bList.add(new B(3)); bList.add(new B(4)); } private int i = -1; public void am1(){ i++; if(i>= bList.size()) { c.cm1(); }else { B b = bList.get(i); b.bm1(this); //System.out.println("method 1 in a----" + i); } } } ``` ```java public class B { private int id; public B(int id) { this.id = id; } public void bm1(A a){ System.out.println("method 1 in B before*****" + id); a.am1(); System.out.println("method 1 in b after -----" + id); } } ``` ```java public class Main { public static void main(String[] args) { A a = new A(); a.am1(); } } ``` 执行的结果: ``` method 1 in B before*****1 method 1 in B before*****2 method 1 in B before*****3 method 1 in B before*****4 method 1 in c----- method 1 in b after -----4 method 1 in b after -----3 method 1 in b after -----2 method 1 in b after -----1 ``` # 3. Struts2 拦截器源码实现模拟 在interceptorfilterdemo包下,是对Struts2 的拦截器以及Filter的完整模拟实现。最核心的代码如下: ```java public class HandlerChain { private List interceptors = new ArrayList<>(); private Iterator iterator = null; private Handler handler = new HandlerImpl1(); public HandlerChain(){ interceptors.add(new InterceptorImpl1()); interceptors.add(new InterceptorImpl2()); // interceptors.add(new InterceptorImpl3()); //有这个拦截器,handler不会执行。 iterator = interceptors.iterator(); //每次调用iterator都会产生一个新的Iterator对象,通过在这里调用,只会产生一个,这样handler方法的实现才会有效。 } public void handle(){ if(iterator.hasNext()) { iterator.next().interceptor(this); }else{ handler.handle(); } } } ``` 这个链的实现类似于这种场景。4个人:班长,3个同学(A,B,C),班长需要7块买包烟,先跟A借一块,再跟B借一块,再跟C借一块,(A,B,C是拦截器角色),最后跟其他人借一块(其他人是Handler对象),此时只有4块钱,又反过来跟C借一块,B借一块,A借一块 。如果中途某个人不借(A,B,C),整个流程终止,已经借到的钱需要还回去。 在Struts2的源代码中,主要查看以下两个地方来看Struts2中拦截器的实现与使用 - ActionInvocation类 - Interceptor接口 # 4. Spring Mvc 拦截器源码实现模拟 在interceptorimpl包下,是对Spring mvc 的拦截器的模拟实现。最核心的代码如下: ```java public class HandlerChain { private List interceptors = new ArrayList<>(); private Handler handler = new HandlerImpl1(); //记录当前执行到了哪一个拦截器,以后后续反向执行 private int interceptorIndex = -1; public HandlerChain(){ interceptors.add(new Interceptor1()); interceptors.add(new Interceptor2()); //这个注释掉,看另外的情况 interceptors.add(new Interceptor3()); } public boolean applyPreHandle(){ for(int i=0; i< interceptors.size();i++) { Interceptor interceptor = interceptors.get(i); if(interceptor.preHandle()== false) { triggerAfterCompletion(); return false; } interceptorIndex = i; } return true; } public void applyPostHandle(){ for(int i=interceptors.size()-1; i>=0 ;i--) { Interceptor interceptor = interceptors.get(i); interceptor.postHandle(); } } private void triggerAfterCompletion(){ for(int i= interceptorIndex;i>=0;i--) { Interceptor interceptor = interceptors.get(i); interceptor.afterCompletion(); } } } ``` 在Spring Mvc框架中类似的代码,可以在下面几个地方看到 - DispatcherServlet的doDispatch方法看到对拦截器链的调用 - 在HandlerExecutionChain中看到链的实现 - 在Interceptor看到拦截器接口的定义