深度解析Spring?Filter方法示例
更新時間:2023年08月20日 10:28:47 作者:晴天哥_王志
這篇文章主要為大家介紹了深度解析Spring?Filter用法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
Filter的用法
public interface Filter { //初始化方法,整個生命周期中只執(zhí)行一次。 //在init方法成功(失敗如拋異常等)執(zhí)行完前,不能提供過濾服務。 //參數(shù)FilterConfig用于獲取初始化參數(shù) public void init(FilterConfig filterConfig) throws ServletException; //執(zhí)行過濾任務的方法,參數(shù)FilterChain表示過濾器鏈,doFilter方法中只有執(zhí)行chain.doFilter()后才能調(diào)用下一個過濾器的doFilter方法 //才能將請求交經(jīng)下一個Filter或Servlet執(zhí)行 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; //銷毀方法,當移出服務時由web容器調(diào)用。整個生命周期中destroy方法只會執(zhí)行一次 //destroy方法可用于釋放持有的資源,如內(nèi)存、文件句柄等 public void destroy(); }
- Filter的接口定義包含init、doFilter、destroy等接口。
@Component public class TimeFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("time filter init"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("time filter start"); long startTime = System.currentTimeMillis(); filterChain.doFilter(servletRequest, servletResponse); long endTime = System.currentTimeMillis(); System.out.println("time filter consume " + (endTime - startTime) + " ms"); System.out.println("time filter end"); } @Override public void destroy() { System.out.println("time filter init"); } }
- 自定義 Filter對象需要實現(xiàn)Filter的接口并實現(xiàn)其中的方法。
Filter的初始化
public class StandardContext extends ContainerBase implements Context, NotificationEmitter { private HashMap<String, FilterDef> filterDefs = new HashMap<>(); private HashMap<String, ApplicationFilterConfig> filterConfigs = new HashMap<>(); @Override protected synchronized void startInternal() throws LifecycleException { // 省略其他代碼 if (ok) { if (!filterStart()) { log.error(sm.getString("standardContext.filterFail")); ok = false; } } } public boolean filterStart() { boolean ok = true; synchronized (filterConfigs) { filterConfigs.clear(); // 遍歷filterDefs的map初始化Filter對象 for (Entry<String,FilterDef> entry : filterDefs.entrySet()) { String name = entry.getKey(); try { ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, entry.getValue()); filterConfigs.put(name, filterConfig); } catch (Throwable t) { ok = false; } } } return ok; } }
- StandardContext#filterStart負責遍歷filterDefs并創(chuàng)建ApplicationFilterConfig對象。
- ApplicationFilterConfig是包含 Filter 實例的對象,F(xiàn)ilterDef是包含的過濾器的定義。
- StandardContext的filterDefs保存 Filter 的定義,filterConfigs保存 Filter 的實例包裝對象ApplicationFilterConfig。
Filter核心類定義
public class FilterDef implements Serializable { private static final long serialVersionUID = 1L; private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private String description = null; private String displayName = null; private transient Filter filter = null; private String filterClass = null; private String filterName = null; private String largeIcon = null; private final Map<String, String> parameters = new HashMap<>(); private String smallIcon = null; private String asyncSupported = null; }
- FilterDef是Filter的定義類,filterClass表示過濾器的定義類。
public final class ApplicationFilterConfig implements FilterConfig, Serializable { private static final long serialVersionUID = 1L; static final StringManager sm = StringManager.getManager(Constants.Package); private static final List<String> emptyString = Collections.emptyList(); private final transient Context context; private transient Filter filter = null; private final FilterDef filterDef; private transient InstanceManager instanceManager; private ObjectName oname; ApplicationFilterConfig(Context context, FilterDef filterDef) throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException, InvocationTargetException, NamingException, IllegalArgumentException, NoSuchMethodException, SecurityException { super(); this.context = context; this.filterDef = filterDef; if (filterDef.getFilter() == null) { getFilter(); } else { this.filter = filterDef.getFilter(); getInstanceManager().newInstance(filter); initFilter(); } } Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException, InvocationTargetException, NamingException, IllegalArgumentException, NoSuchMethodException, SecurityException { if (this.filter != null) return (this.filter); // 創(chuàng)建 并初始化 Filter 對象 String filterClass = filterDef.getFilterClass(); this.filter = (Filter) getInstanceManager().newInstance(filterClass); initFilter(); return (this.filter); } private void initFilter() throws ServletException { if (context instanceof StandardContext && context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); filter.init(this); } finally { String capturedlog = SystemLogHandler.stopCapture(); if (capturedlog != null && capturedlog.length() > 0) { getServletContext().log(capturedlog); } } } else { filter.init(this); } registerJMX(); } }
- ApplicationFilterConfig的創(chuàng)建過程就是通過實例化FilterDef的 filterClass的類并調(diào)用 Filter 的 init 方法初始化 Filter 對象。
- initFilter方法負責初始化 Filter 對象,也就是調(diào)用 filter 的 init 方法。
- ApplicationFilterConfig的filter字段保存實例話后的 Filter 實例。
FilterDef的加載
FilterDef 的來源需要如果是 web.xml 定義那么就從 webxml 中獲取,如果是springboot 工程,就通過ApplicationContextFacade類型進行獲取。
public class ContextConfig implements LifecycleListener { private void configureContext(WebXml webxml) { // 省略相關(guān)代碼 for (FilterDef filter : webxml.getFilters().values()) { if (filter.getAsyncSupported() == null) { filter.setAsyncSupported("false"); } context.addFilterDef(filter); } } }
- 通過webxml.getFilters()獲取過濾器的FilterDef并添加到StandardContext對象當中。
- 上述方式一般在 spring MVC 項目在 web.xml 配置過濾器的時候使用。
public class ApplicationContextFacade implements org.apache.catalina.servlet4preview.ServletContext { @Override public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { if (SecurityUtil.isPackageProtectionEnabled()) { return (FilterRegistration.Dynamic) doPrivileged("addFilter", new Class[]{String.class, Filter.class}, new Object[]{filterName, filter}); } else { return context.addFilter(filterName, filter); } } } public class ApplicationContext implements org.apache.catalina.servlet4preview.ServletContext { private FilterRegistration.Dynamic addFilter(String filterName, String filterClass, Filter filter) throws IllegalStateException { FilterDef filterDef = context.findFilterDef(filterName); // context是StandardContext對象 if (filterDef == null) { filterDef = new FilterDef(); filterDef.setFilterName(filterName); context.addFilterDef(filterDef); } else { if (filterDef.getFilterName() != null && filterDef.getFilterClass() != null) { return null; } } if (filter == null) { filterDef.setFilterClass(filterClass); } else { filterDef.setFilterClass(filter.getClass().getName()); filterDef.setFilter(filter); } return new ApplicationFilterRegistration(filterDef, context); } }
- 通過ApplicationContextFacade的addFilter方法并最終調(diào)用ApplicationContext的addFilter方法將過濾器的FilterDef并添加到StandardContext對象當中。
- 是上述方式一般在springboot 工程中的加載過程。
Filter的加載流程
- Filter的定義的加載順序如上圖所示,包括解析 web.xml 文件生成 FilterDef并保存到 StandardContext 當中,遍歷 StandardContext 的 FilterDef 生成ApplicationFilterConfig并保存到StandardContext當中。
- StandardContext負責保存核心的FilterDef和ApplicationFilterConfig。
Filter執(zhí)行
Filter整體流程
final class StandardWrapperValve extends ValveBase { @Override public final void invoke(Request request, Response response) throws IOException, ServletException { // 省略相關(guān)代碼 ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet); try { if ((servlet != null) && (filterChain != null)) { if (context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); if (request.isAsyncDispatching()) { request.getAsyncContextInternal().doInternalDispatch(); } else { filterChain.doFilter(request.getRequest(), response.getResponse()); } } finally { } } else { if (request.isAsyncDispatching()) { request.getAsyncContextInternal().doInternalDispatch(); } else { filterChain.doFilter (request.getRequest(), response.getResponse()); } } } } catch (Throwable e) { } // Release the filter chain (if any) for this request if (filterChain != null) { filterChain.release(); } } }
- Filter 執(zhí)行流程在StandardWrapperValve#invoke 方法當中,核心流程包括創(chuàng)建 Filter 調(diào)用鏈和執(zhí)行 Filter 調(diào)用鏈。
- ApplicationFilterFactory.createFilterChain負責創(chuàng)建調(diào)用鏈對象ApplicationFilterChain。
- filterChain.doFilter負責執(zhí)行 Filter 調(diào)用鏈。
filterChain的構(gòu)建
public final class ApplicationFilterChain implements FilterChain { public static final int INCREMENT = 10; private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; private int pos = 0; private int n = 0; private Servlet servlet = null; private boolean servletSupportsAsync = false; private static final StringManager sm = StringManager.getManager(Constants.Package); void addFilter(ApplicationFilterConfig filterConfig) { for(ApplicationFilterConfig filter:filters) if(filter==filterConfig) return; if (n == filters.length) { ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT]; System.arraycopy(filters, 0, newFilters, 0, n); filters = newFilters; } filters[n++] = filterConfig; } }
- ApplicationFilterChain的內(nèi)部維護ApplicationFilterConfig[] filters來保存 Filter 對象。
public final class ApplicationFilterFactory { public static ApplicationFilterChain createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet) { ApplicationFilterChain filterChain = null; if (request instanceof Request) { Request req = (Request) request; if (Globals.IS_SECURITY_ENABLED) { filterChain = new ApplicationFilterChain(); } else { filterChain = (ApplicationFilterChain) req.getFilterChain(); if (filterChain == null) { filterChain = new ApplicationFilterChain(); req.setFilterChain(filterChain); } } } else { filterChain = new ApplicationFilterChain(); } filterChain.setServlet(servlet); filterChain.setServletSupportsAsync(wrapper.isAsyncSupported()); // 通過StandardContext#findFilterMaps獲取所有的Filter對象 StandardContext context = (StandardContext) wrapper.getParent(); FilterMap filterMaps[] = context.findFilterMaps(); if ((filterMaps == null) || (filterMaps.length == 0)) return (filterChain); DispatcherType dispatcher = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); String requestPath = null; Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); if (attribute != null){ requestPath = attribute.toString(); } String servletName = wrapper.getName(); // 匹配路徑 Add the relevant path-mapped filters to this filter chain for (int i = 0; i < filterMaps.length; i++) { if (!matchDispatcher(filterMaps[i] ,dispatcher)) { continue; } if (!matchFiltersURL(filterMaps[i], requestPath)) continue; // 通過StandardContext#findFilterConfig獲取Filter對象 ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { continue; } filterChain.addFilter(filterConfig); } // 匹配servlet的名字 Add filters that match on servlet name second for (int i = 0; i < filterMaps.length; i++) { if (!matchDispatcher(filterMaps[i] ,dispatcher)) { continue; } if (!matchFiltersServlet(filterMaps[i], servletName)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } filterChain.addFilter(filterConfig); } // Return the completed filter chain return filterChain; } }
- 獲取StandardContext的FilterMap[] 對象,遍歷FilterMap[]后進行規(guī)則匹配,匹配后通過 StandardContext 獲取ApplicationFilterConfig對象添加到ApplicationFilterChain當中。
- StandardContext本身維護的ApplicationFilterConfig的加載流程已經(jīng)分析,需要了解FilterMap的加載過程。
Filter 執(zhí)行流程
public final class ApplicationFilterChain implements FilterChain { public static final int INCREMENT = 10; private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; private int pos = 0; private int n = 0; private Servlet servlet = null; private boolean servletSupportsAsync = false; private static final StringManager sm = StringManager.getManager(Constants.Package); @Override public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if( Globals.IS_SECURITY_ENABLED ) { // 省略相關(guān)代碼 } else { internalDoFilter(request,response); } } private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; try { Filter filter = filterConfig.getFilter(); if( Globals.IS_SECURITY_ENABLED ) { // 省略相關(guān)代碼 } else { filter.doFilter(request, response, this); } } catch (IOException | ServletException | RuntimeException e) { } catch (Throwable e) { } return; } try { if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse) && Globals.IS_SECURITY_ENABLED ) { // 省略相關(guān)代碼 } else { servlet.service(request, response); } } catch (IOException | ServletException | RuntimeException e) { } catch (Throwable e) { } finally { } } }
- ApplicationFilterChain#internalDoFilter負責 Filter 調(diào)用鏈的執(zhí)行,內(nèi)部通過維護 Filter 的對象數(shù)組filters和下標pos依次執(zhí)行 Filter。
FilterMap介紹
/** * 來看下這個類的官方解釋: * Web應用程序的過濾器映射的表示形式,如部署描述符中<filter-mapping>元素中的所示 * 每個過濾器映射都必須包含過濾器名稱以及URL模式或servlet名稱 * 例如以下配置: * <filter-mapping> * <filter-name>MyFilter</filter-name> * <url-pattern>/my</url-pattern> * </filter-mapping> * * 說白了,這個FilterMap就是封裝了配置信息中<filter-mapping>標簽中的元素 * 其中還包含了兩個重點屬性:過濾器名、過濾器對應過濾的url */ public class FilterMap extends XmlEncodingBase implements Serializable { private boolean matchAllUrlPatterns = false; private boolean matchAllServletNames = false; // serverlet的名字,對應多個 private String[] servletNames = new String[0]; // 過濾器名,對應的是<filter-name>中的內(nèi)容 private String filterName = null; // 過濾url,對應的是<url-pattern>中的內(nèi)容(可配置多個<filter-mapping>匹配不同的url,因此是數(shù)組形式) private String[] urlPatterns = new String[0]; }
- FilterMap的核心字段包括匹配的 Url格式,對應的 Filter 對象的filterName等。
FilterMap的加載
public class ContextConfig implements LifecycleListener { private void configureContext(WebXml webxml) { // 省略相關(guān)代碼 for (FilterMap filterMap : webxml.getFilterMappings()) { context.addFilterMap(filterMap); } } }
- 通過webxml.getFilterMappings()獲取過濾器的filterMap并添加到StandardContext中。
- 上述方式一般在 spring MVC 項目在 web.xml 配置過濾器的時候使用。
public class ApplicationFilterRegistration implements FilterRegistration.Dynamic { private static final StringManager sm = StringManager.getManager(Constants.Package); private final FilterDef filterDef; private final Context context; public ApplicationFilterRegistration(FilterDef filterDef, Context context) { this.filterDef = filterDef; this.context = context; } @Override public void addMappingForServletNames( EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... servletNames) { FilterMap filterMap = new FilterMap(); filterMap.setFilterName(filterDef.getFilterName()); if (dispatcherTypes != null) { for (DispatcherType dispatcherType : dispatcherTypes) { filterMap.setDispatcher(dispatcherType.name()); } } if (servletNames != null) { for (String servletName : servletNames) { filterMap.addServletName(servletName); } if (isMatchAfter) { context.addFilterMap(filterMap); } else { context.addFilterMapBefore(filterMap); } } } @Override public void addMappingForUrlPatterns( EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... urlPatterns) { FilterMap filterMap = new FilterMap(); filterMap.setFilterName(filterDef.getFilterName()); if (dispatcherTypes != null) { for (DispatcherType dispatcherType : dispatcherTypes) { filterMap.setDispatcher(dispatcherType.name()); } } if (urlPatterns != null) { for (String urlPattern : urlPatterns) { filterMap.addURLPattern(urlPattern); } if (isMatchAfter) { context.addFilterMap(filterMap); } else { context.addFilterMapBefore(filterMap); } } } }
- addMappingForServletNames和addMappingForUrlPatterns負責獲取過濾器的filterMap并添加到StandardContext中。
- 上述方式一般在 spring boot 工程中加載FilterMap使用。
Filter執(zhí)行流程圖
- 通過解析 web.xml 文件生成 FilterMap并保存到 StandardContext 當中。
- ApplicationFilterChaiFactory 負責創(chuàng)建 Filter 對象 ApplicationFilterChain,然后遍歷FilterMap s并添加符合的 Filter 包裝對象 ApplicationFilterConfig。
- 執(zhí)行ApplicationFilterChain的doFilter方法調(diào)用過濾器。
以上就是深度解析Spring Filter方法示例的詳細內(nèi)容,更多關(guān)于Spring Filter用法的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
深度deepin安裝以及jdk、tomcat、Nginx安裝教程
這篇文章主要給大家介紹了關(guān)于深度deepin安裝以及jdk、tomcat、Nginx安裝的相關(guān)資料,按照文中介紹的方法可以輕松的實現(xiàn)安裝,對大家的工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01Spring rest接口中的LocalDateTime日期類型轉(zhuǎn)時間戳
這篇文章主要介紹了Spring rest接口中的LocalDateTime日期類型轉(zhuǎn)時間戳的方法,Java程序中一般將日期類型定義為LocalDateTime,數(shù)據(jù)庫中保存的時間是0時區(qū)的時間2023-03-03Springboot 在普通類型注入Service或mapper
這篇文章主要介紹了Springboot 在普通類型注入Service或mapper,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11Java使用Apache Commons高效處理CSV文件的操作指南
在 Java 開發(fā)中,CSV(Comma-Separated Values,逗號分隔值)是一種常見的數(shù)據(jù)存儲格式,廣泛用于數(shù)據(jù)交換和簡單的存儲任務,本文將介紹Java使用Apache Commons高效處理CSV文件的操作指南,需要的朋友可以參考下2025-03-03Simple Java Mail郵件發(fā)送實現(xiàn)過程解析
這篇文章主要介紹了Simple Java Mail郵件發(fā)送實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-11-11