javascript
SpringMVC源码阅读:过滤器
SpringMVC源碼閱讀:過濾器
目錄
- 1.前言
- 2.源碼分析
- 3.自定義過濾器
- 3.1 自定義過濾器繼承OncePerRequestFilter
- 3.2 自定義過濾器實現Filter接口
- 4.過濾器(Filter)和攔截器(Interceptor)的區別
- 4.1 過濾器:
- 4.2 攔截器:
- 5.總結:
- 6.參考
?
正文
回到頂部1.前言
SpringMVC是目前J2EE平臺的主流Web框架,不熟悉的園友可以看SpringMVC源碼閱讀入門,它交代了SpringMVC的基礎知識和源碼閱讀的技巧
本文將通過源碼(基于Spring4.3.7)分析,弄清楚SpringMVC過濾器是如何執行的,并自定義過濾器,分清楚過濾器和攔截器的區別
回到頂部2.源碼分析
web.xml配置
<filter><!--過濾器名稱--><filter-name>Set Character Encoding</filter-name><!--過濾器處理類--><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><!--初始化參數--><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>Set Character Encoding</filter-name><!--攔截路徑--><url-pattern>/*</url-pattern></filter-mapping>打開CharacterEncoding類,該類為request設置字符編碼,打開類繼承圖
CharacterEncodingFilter重寫父類OncePerRequestFilter的doFilterInterval方法
forceRequestEncoding為True
188行獲取編碼
191行為request設置編碼
194行為response設置編碼
197行調用FilterChain
打開CharcterEncodingFilter的父類OncePerRequestFilter,OncePerRequestFilter保證請求分發執行一次Filter
CharcterEncodingFilter實現Filter接口的doFilter方法,打開之
96行獲取屬性,該屬性表明這個方法是否被過濾
98行hasAlreadyFilteredAttribute表明這個方法是否被過濾;skipDispatch方法判斷是否跳過分發;shouldNotFilter方法默認返回False,被子類重寫,然而,CharacterEncodingFilter類并未重寫,ForwardedHeaderFilter重寫該方法,暫時不看
101行直接調用FilterChain的doFilter方法,FilterChain部分
98行的上述條件都不滿足,則進入105行,為request設置“已過濾”標識
107行調用子類CharacterEncodingFilter的doFilterInterval方法
繼續深入,打開OncePerRequestFilter類的父類GenericFilterBean類
重點看init方法,該方法啟動服務才會進入,主要負責獲取web.xml里配置的參數
?
180行獲取FilterConfig
filterClass和filterName是我們在web.xml配置的屬性
184行獲取<init-param>里屬性
?
185行聲明BeanWrapper,一個通用的JavaBean接口,封裝了setget方法,在SpringMVC源碼閱讀:屬性編輯器、數據綁定我已經講過
186行聲明資源加載器,加載classpath和文件系統
189行給屬性設置True
199行initFilterBean方法被子類重寫,用于補充初始化方法,OncePerRequestFilter未重寫,我們暫時不看
回到頂部3.自定義過濾器
現在Web項目基本都是前后端分離的,不可避免地要解決跨域問題??碏ilter接口繼承圖,發現CorsFilter可以處理跨域,但是并不方便
什么是跨域?
前端地址和后臺地址的
IP一致,端口不一致
IP不一致,端口不一致
IP不一致,端口一致
都屬于跨域范疇
前端代碼如下
<!DOCTYPE html> <html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><!-- <link rel="stylesheet" href=""> --><style></style> </head><body><script></script><script type="text/javascript" src="jquery-3.1.1.min.js"></script><script type="text/javascript">$.ajax({url: "http://localhost:8080/springmvcdemo/employee/detail/8",data: {},success: function (data) {console.log(html)},dataType: "json"});</script></body></html>將前端代碼地址設置為http://localhost:1234,VSCode可以做,不贅述。后臺代碼地址http://localhost:8080,因為端口不一致,形成了跨域,不做跨域處理,直接訪問有如下效果
現在我們來自定義過濾器解決跨域問題
3.1 自定義過濾器繼承OncePerRequestFilter
web.xml
<filter><!--過濾器名稱--><filter-name>CorsFilter</filter-name><!--過濾器處理類--><filter-class>org.format.demo.custom.ExtendedCorsFilter</filter-class></filter><filter-mapping><filter-name>CorsFilter</filter-name><!--攔截路徑--><url-pattern>/*</url-pattern></filter-mapping>ExtendedCorsFilter.java,重寫doFilterInterval方法
public class ExtendedCorsFilter extends OncePerRequestFilter{@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {response.addHeader("Access-Control-Allow-Origin", "*");response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");response.addHeader("Access-Control-Allow-Headers", "Content-Type");filterChain.doFilter(request,response);}}此時再運行前端代碼,已經成功請求到結果
Headers設置成功
3.2 自定義過濾器實現Filter接口
web.xml配置如下
<filter><!--過濾器名稱--><filter-name>CorsFilter</filter-name><!--過濾器處理類--><filter-class>org.format.demo.custom.ImplementedCorsFilter</filter-class><!--初始化參數--><init-param><param-name>allowedOrigins</param-name><param-value>*</param-value></init-param><init-param><param-name>allowedMethods</param-name><param-value>*</param-value></init-param><init-param><param-name>allowedHeaders</param-name><param-value>*</param-value></init-param></filter>?
ImplementedCorsFilter.java
public class ImplementedCorsFilter implements Filter{//允許的請求域private String allowedOrigins;//允許的請求方法private String allowedMethods;//允許的請求頭private String allowedHeaders;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {this.allowedOrigins = filterConfig.getInitParameter("allowedOrigins");this.allowedMethods = filterConfig.getInitParameter("allowedMethods");this.allowedHeaders = filterConfig.getInitParameter("allowedHeaders");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletResponse rsp = (HttpServletResponse) response;rsp.setHeader("Access-Control-Allow-Origin", allowedOrigins);rsp.setHeader("Access-Control-Allow-Methods", allowedMethods);rsp.setHeader("Access-Control-Allow-Headers", allowedHeaders);chain.doFilter(request, response);}@Overridepublic void destroy() {} }相比繼承OncePerRequestFilter方法,實現Filter接口可以通過重寫init方法獲取web.xml屬性值,效果一致
回到頂部4.過濾器(Filter)和攔截器(Interceptor)的區別
我在SpringMVC源碼閱讀:攔截器詳細講解了SpringMVC攔截器的工作原理
過濾器先于攔截器執行,后于攔截器執行結束
4.1 過濾器:
依賴于servlet容器。在實現上基于函數回調,可以對幾乎所有請求進行過濾,但是缺點是一個過濾器實例只能在容器初始化時調用一次。使用過濾器的目的是用來做一些過濾操作,獲取我們想要獲取的數據.
比如:在過濾器中修改字符編碼;在過濾器中修改HttpServletRequest的一些參數,包括:過濾低俗文字、危險字符等
4.2 攔截器:
依賴于web框架,在SpringMVC中就是依賴于SpringMVC框架。在實現上基于Java的反射機制,屬于面向切面編程(AOP)的一種運用。由于攔截器是基于Web框架的調用。
因此可以使用spring的依賴注入(DI)進行一些業務操作,同時一個攔截器實例在一個controller生命周期之內可以多次調用。但是缺點是只能對controller請求進行攔截,對其他的一些比如直接訪問靜態資源的請求則沒辦法進行攔截處理。
總結:業務中盡量使用基于方法的攔截器,在進行一些需要統一處理的業務可以使用基于Servlet的過濾器
回到頂部5.總結:
Filter接口用來執行過濾任務
CompositeFilter實現filter,用到了組合設計模式
抽象類GenericFilterBean實現Filter接口,負責解析web.xml的Filter的init-param中參數,是所有過濾器的父類。init方法解析web.xml的參數
抽象類OncePerRequestFilter繼承GenericFilterBean,doFilter方法根據hasAlreadyFilteredAttribute判斷是否執行過濾
CharacterEncodingFilter重寫父類OncePerRequestFilter的doFilterInterval方法,調用FilterChain的doDilter方法執行過濾邏輯
其他過濾器園友可以自行查看,不再贅述,demo源碼
回到頂部6.參考
https://docs.spring.io/spring/docs/4.3.7.RELEASE/spring-framework-reference/htmlsingle/#beans-beans-conversion
https://docs.spring.io/spring/docs/current/javadoc-api/
https://github.com/spring-projects/spring-framework
文中難免有不足,歡迎指正
原文地址https://www.cnblogs.com/Java-Starter/p/10444617.html
總結
以上是生活随笔為你收集整理的SpringMVC源码阅读:过滤器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 完美立方2810
- 下一篇: 如何接入虹软免费人脸识别SDK