Servlet Filter過濾器執(zhí)行順序
Servlet中的過濾器相當于守護后臺資源的一道關卡,我們可以在過濾器中進行身份校驗、權限認證、請求過濾等。
過濾器本身并不難,我們只需要知道他的定義方法、作用范圍、執(zhí)行順序即可。
網(wǎng)上對于過濾器執(zhí)行順序的描述可能會讓人產(chǎn)生誤解。
圖片來源于網(wǎng)絡
客戶端請求到達的時候,經(jīng)過一次過濾器。
服務器處理完請求的時候,經(jīng)過一次過濾器。
雖然經(jīng)過兩次過濾器,但不代表同樣的代碼執(zhí)行了兩次。
下面做了個簡單的測試,看下執(zhí)行結果就應該知道真正的執(zhí)行流程了。
測試環(huán)境
tomcat9(servlet4.0)
jdk1.8
新版servlet可以通過注解注冊servlet組件以及過濾器,無需再到web.xml下注冊了。
測試過程
測試之間要先知道filterChain(過濾鏈)是干嘛的。
一個過濾器處理完后,會把request和response對象通過filterchain傳遞給下一個過濾器,如果沒有下一個過濾器,則會直接開始執(zhí)行業(yè)務代碼,
單個過濾器
定義一個過濾器A
@WebFilter(value = "/*", filterName="A") public class FilterA implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(format.format(new Date())); System.out.println("A:攔截1"); chain.doFilter(request, response); System.out.println(format.format(new Date())); System.out.println("A:攔截2"); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
定義一個servlet,sleep5秒
@WebServlet("/mainUrl") public class MainController extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public MainController() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
運行結果
2020-12-01 10:46:50 A:攔截1 2020-12-01 10:46:55 A:攔截2
執(zhí)行順序:
filterChain之前的代碼 ——>業(yè)務處理——>filterChain之后的代碼。
多個過濾器
servlet的注解在多個過濾器的情況下,是按照過濾器的名稱來排序的,例如A開頭的過濾器,在B開頭的后面。
A過濾器
@WebFilter(value = "/*", filterName="A") public class FilterA implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(format.format(new Date())); System.out.println("A:攔截1"); chain.doFilter(request, response); System.out.println(format.format(new Date())); System.out.println("A:攔截2"); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
B過濾器
@WebFilter(value = "/*", filterName="B") public class FilterB implements Filter{ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(format.format(new Date())); System.out.println("B:攔截1"); chain.doFilter(request, response); System.out.println(format.format(new Date())); response.setContentType("normal content"); System.out.println("B:攔截2"); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
運行結果:
2020-12-01 10:53:00 A:攔截1 2020-12-01 10:53:00 B:攔截1 2020-12-01 10:53:05 B:攔截2 2020-12-01 10:53:05 A:攔截2
執(zhí)行順序:
B:攔截1和B:攔截2之間,停頓了5秒處理業(yè)務。所以先執(zhí)行了 chain.doFilter前的 A、B過濾器代碼,處理完業(yè)務返回的時候正好相反,先返回執(zhí)行B的代碼,再執(zhí)行的A的代碼。
總結
再來看這個圖,可以略微改一下了。
分界線是filterChain過濾鏈,請求進來的時候,執(zhí)行filterchain之前的代碼,返回response的時候,執(zhí)行filterchain之后的代碼。
多個過濾器之間的執(zhí)行順序,滿足“先進后出” (棧結構)的原則。
其他
如果在測試過程中,發(fā)現(xiàn)過濾器執(zhí)行了很多次,那么也可能是因為測試環(huán)境中包含了某些靜態(tài)資源。
過濾器A
@WebFilter(value = "/*", filterName="A") public class FilterA implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(format.format(new Date())); System.out.println("A:攔截1"); chain.doFilter(request, response); System.out.println(format.format(new Date())); System.out.println("A:攔截2"); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
過濾器B
@WebFilter(value = "/*", filterName="B") public class FilterB implements Filter{ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub HttpServletRequest req = (HttpServletRequest) request; SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(req.getRequestURL()); System.out.println(format.format(new Date())); System.out.println("B:攔截1"); chain.doFilter(request, response); System.out.println(format.format(new Date())); response.setContentType("normal content"); System.out.println("B:攔截2"); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
主程序
@WebServlet("/mainUrl") public class MainController extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public MainController() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } request.getRequestDispatcher("/WEB-INF/pages/main.jsp").forward(request, response); // response.sendRedirect("/WEB-INF/pages/main.jsp"); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
執(zhí)行結果:
2020-12-01 11:09:38 A:攔截1 http://localhost:8080/StudentManage/mainUrl 2020-12-01 11:09:38 B:攔截1 2020-12-01 11:09:43 B:攔截2 2020-12-01 11:09:43 A:攔截2 2020-12-01 11:09:44 A:攔截1 http://localhost:8080/StudentManage/css/bootstrap.css.map 2020-12-01 11:09:44 B:攔截1 2020-12-01 11:09:44 B:攔截2 2020-12-01 11:09:44 A:攔截2
轉發(fā)(forward)的頁面中需要請求靜態(tài)資源,再次觸發(fā)了過濾器。
以上就是Servlet Filter過濾器執(zhí)行順序的詳細內容,更多關于Servlet Filter過濾器的資料請關注腳本之家其它相關文章!
- 淺談SpringMVC的攔截器(Interceptor)和Servlet 的過濾器(Filter)的區(qū)別與聯(lián)系 及SpringMVC 的配置文件
- JavaWeb Servlet中Filter過濾器的詳解
- servlet過濾器(Filter)詳解(九)
- 詳解Servlet之過濾器(Filter)
- Spring Boot使用Servlet及Filter過程詳解
- springboot掃描自定義的servlet和filter代碼詳解
- SpringBoot初始教程之Servlet、Filter、Listener配置詳解
- 詳談Servlet和Filter的區(qū)別以及兩者在Struts2和Springmvc中的應用
- web.xml中servlet, bean, filter, listenr 加載順序_動力節(jié)點Java學院整理
- Filter、Servlet、Listener的學習_動力節(jié)點Java學院整理
- Spring Boot 編寫Servlet、Filter、Listener、Interceptor的方法
- 解決cannot be cast to javax.servlet.Filter 報錯的問題
相關文章
Spring Boot 中的 @PutMapping 注解原理及使用小結
在本文中,我們介紹了 Spring Boot 中的 @PutMapping 注解,它可以將 HTTP PUT 請求映射到指定的處理方法上,我們還介紹了 @PutMapping 注解的原理以及如何在 Spring Boot 中使用它,感興趣的朋友跟隨小編一起看看吧2023-12-12Java Socket+mysql實現(xiàn)簡易文件上傳器的代碼
最近在做一個小項目,項目主要需求是實現(xiàn)一個文件上傳器,通過客戶端的登陸,把本地文件上傳到服務器的數(shù)據(jù)庫(本地的)。下面通過本文給大家分享下實現(xiàn)代碼,感興趣的朋友一起看看吧2016-10-10Eclipse+Java+Swing實現(xiàn)圖書管理系統(tǒng)(詳細代碼)
這篇文章主要介紹了Eclipse+Java+Swing實現(xiàn)圖書管理系統(tǒng)并附上詳細代碼,需要的小伙伴可以參考一下,希望對你有所幫助2022-01-01Spring Security動態(tài)權限的實現(xiàn)方法詳解
這篇文章主要和小伙伴們簡單介紹下 Spring Security 中的動態(tài)權限方案,以便于小伙伴們更好的理解 TienChin 項目中的權限方案,感興趣的可以了解一下2022-06-06Java ScheduledExecutorService的具體使用
ScheduledExecutorService有線程池的特性,也可以實現(xiàn)任務循環(huán)執(zhí)行,本文主要介紹了Java ScheduledExecutorService的具體使用,具有一定的參考價值,感興趣的可以了解一下2023-05-05