Spring Filter深度分析

手机软件开发 2024-9-19 15:27:07 49 0 来自 中国
Filter的用法

public interface Filter {    //初始化方法,整个生命周期中只实验一次。    //在init方法乐成(失败如抛非常等)实验完前,不能提供过滤服务。    //参数FilterConfig用于获取初始化参数    public void init(FilterConfig filterConfig) throws ServletException;    //实验过滤使命的方法,参数FilterChain表现过滤器链,doFilter方法中只有实验chain.doFilter()后才气调用下一个过滤器的doFilter方法    //才气将哀求交经下一个Filter或Servlet实验    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;    //销毁方法,当移出服务时由web容器调用。整个生命周期中destroy方法只会实验一次    //destroy方法可用于开释持有的资源,如内存、文件句柄等    public void destroy();}

  • Filter的接口界说包罗init、doFilter、destroy等接口。
@Componentpublic 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对象须要实现Filter的接口并实现此中的方法。


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并创建ApplicationFilterConfig对象。
  • ApplicationFilterConfig是包罗 Filter 实例的对象,FilterDef是包罗的过滤器的界说。
  • 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);        // 创建 并初始化 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的创建过程就是通过实例化FilterDef的 filterClass的类并调用 Filter 的 init 方法初始化 Filter 对象。
  • initFilter方法负责初始化 Filter 对象,也就是调用 filter 的 init 方法。
  • ApplicationFilterConfig的filter字段生存实例话后的 Filter 实例。


FilterDef的加载

FilterDef 的泉源须要如果是 web.xml 界说那么就从 webxml 中获取,如果是springboot 工程,就通过ApplicationContextFacade范例举行获取。
public class ContextConfig implements LifecycleListener {    private void configureContext(WebXml webxml) {        // 省略相干代码        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方法并终极调用ApplicationContext的addFilter方法将过滤器的FilterDef并添加到StandardContext对象当中。
  • 是上述方式一样平常在springboot 工程中的加载过程。


Filter的加载流程

1.png

  • Filter的界说的加载序次如上图所示,包罗分析 web.xml 文件天生 FilterDef并生存到 StandardContext 当中,遍历 StandardContext 的 FilterDef 天生ApplicationFilterConfig并生存到StandardContext当中。
  • StandardContext负责生存核心的FilterDef和ApplicationFilterConfig。


Filter实验

Filter团体流程

final class StandardWrapperValve    extends ValveBase {    @Override    public final void invoke(Request request, Response response)        throws IOException, ServletException {        // 省略相干代码        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 实验流程在StandardWrapperValve#invoke 方法当中,核心流程包罗创建 Filter 调用链和实验 Filter 调用链。
  • ApplicationFilterFactory.createFilterChain负责创建调用链对象ApplicationFilterChain。
  • filterChain.doFilter负责实验 Filter 调用链。


filterChain的构建

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的内部维护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 ,dispatcher)) {                continue;            }            if (!matchFiltersURL(filterMaps, requestPath))                continue;            // 通过StandardContext#findFilterConfig获取Filter对象            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)                context.findFilterConfig(filterMaps.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 ,dispatcher)) {                continue;            }            if (!matchFiltersServlet(filterMaps, servletName))                continue;            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)                context.findFilterConfig(filterMaps.getFilterName());            if (filterConfig == null) {                // FIXME - log configuration problem                continue;            }            filterChain.addFilter(filterConfig);        }        // Return the completed filter chain        return filterChain;    }}

  • 获取StandardContext的FilterMap[] 对象,遍历FilterMap[]后举行规则匹配,匹配后通过 StandardContext 获取ApplicationFilterConfig对象添加到ApplicationFilterChain当中。
  • StandardContext自己维护的ApplicationFilterConfig的加载流程已经分析,须要相识FilterMap的加载过程


Filter 实验流程

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 ) {            // 省略相干代码        } 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 ) {                    // 省略相干代码                } 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 ) {                // 省略相干代码            } else {                servlet.service(request, response);            }        } catch (IOException | ServletException | RuntimeException e) {        } catch (Throwable e) {        } finally {        }    }}

  • ApplicationFilterChain#internalDoFilter负责 Filter 调用链的实验,内部通过维护 Filter 的对象数组filters和下标pos依次实验 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>中的内容    private String filterName = null;     // 过滤url,对应的是<url-pattern>中的内容(可设置多个<filter-mapping>匹配差异的url,因此是数组形式)    private String[] urlPatterns = new String[0]; }

  • FilterMap的核心字段包罗匹配的 Url格式,对应的 Filter 对象的filterName等。


FilterMap的加载

public class ContextConfig implements LifecycleListener {    private void configureContext(WebXml webxml) {        // 省略相干代码        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实验流程图



  • 通过分析 web.xml 文件天生 FilterMap并生存到 StandardContext 当中。
  • ApplicationFilterChaiFactory 负责创建 Filter 对象 ApplicationFilterChain,然后遍历FilterMap s并添加符合的 Filter 包装对象 ApplicationFilterConfig。
  • 实验ApplicationFilterChain的doFilter方法调用过滤器。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-25 10:22, Processed in 0.168539 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表