Spring的web包中中有很多过滤器,这些过滤器位于org.springframework.web.filter并且理所当然地实现了javax.servlet.Filter,不过实现的方式有以下几类:

(1) 直接实现Filter,这一类过滤器只有CompositeFilter;

(2) 继承抽象类GenericFilterBean,该类实现了javax.servlet.Filter,这一类的过滤器只有一个,即DelegatingFilterProxy;

(3) 继承抽象类OncePerRequestFilter,该类为GenericFilterBean的直接子类,这一类过滤器包括CharacterEncodingFilter、HiddenHttpMethodFilter、HttpPutFormContentFilter、RequestContextFilter和ShallowEtagHeaderFilter;

(4) 继承抽象类AbstractRequestLoggingFilter,该类为OncePerRequestFilter的直接子类,这一类过滤器包括CommonsRequestLoggingFilter、Log4jNestedDiagnosticContextFilter和ServletContextRequestLoggingFilter。

本文要讲述的,即是GenericFilterBean、OncePerRequestFilter和AbstractRequestLoggingFilter。

GenericFilterBean

抽象类GenericFilterBean实现了javax.servlet.Filter、org.springframework.beans.factory.BeanNameAware、org.springframework.context.EnvironmentAware、org.springframework.web.context.ServletContextAware、org.springframework.beans.factory.InitializingBean和org.springframework.beans.factory.DisposableBean五个接口,作用如下:

(1) Filter,实现过滤器;

(2) BeanNameAware,实现该接口的setBeanName方法,便于Bean管理器生成Bean;

(3) EnvironmentAware,实现该接口的setEnvironment方法,指明该Bean运行的环境;

(4) ServletContextAware,实现该接口的setServletContextAware方法,指明上下文;

(5) InitializingBean,实现该接口的afterPropertiesSet方法,指明设置属性生的操作;

(6) DisposableBean,实现该接口的destroy方法,用于回收资源。

GenericFilterBean的工作流程是:init-doFilter-destory,其中的init和destory在该类中实现,doFilter在具体实现类中实现。init的代码如下:

  1. /**
  2. * Standard way of initializing this filter.
  3. * Map config parameters onto bean properties of this filter, and
  4. * invoke subclass initialization.
  5. * @param filterConfig the configuration for this filter
  6. * @throws ServletException if bean properties are invalid (or required
  7. * properties are missing), or if subclass initialization fails.
  8. * @see #initFilterBean
  9. */
  10. public final void init(FilterConfig filterConfig) throws ServletException {
  11. Assert.notNull(filterConfig, "FilterConfig must not be null");
  12. if (logger.isDebugEnabled()) {
  13. logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'");
  14. }
  15. this.filterConfig = filterConfig;
  16. // Set bean properties from init parameters.
  17. try {
  18. PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);
  19. BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
  20. ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
  21. bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
  22. initBeanWrapper(bw);
  23. bw.setPropertyValues(pvs, true);
  24. }
  25. catch (BeansException ex) {
  26. String msg = "Failed to set bean properties on filter '" +
  27. filterConfig.getFilterName() + "': " + ex.getMessage();
  28. logger.error(msg, ex);
  29. throw new NestedServletException(msg, ex);
  30. }
  31. // Let subclasses do whatever initialization they like.
  32. initFilterBean();
  33. if (logger.isDebugEnabled()) {
  34. logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
  35. }
  36. }

该方法来自于javax.servlet.Filter,即过滤器的初始化,它的主要工作集中于以下几行代码:

  1. // 从properties文件中获取值,这里是web.xml
  2. PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);
  3. // 设置bean适配器
  4. BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
  5. // 设置上下文,这里的servletContext的设定继承自ServletContextAware的setter
  6. ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
  7. // 将上下文信息和环境信息设置到bean适配器中,这里的environment来自于EnvironmentAware的setter
  8. bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
  9. // 初始化bean适配器
  10. initBeanWrapper(bw);
  11. // 将从properties中获取的资源放置到bean适配器
  12. bw.setPropertyValues(pvs, true);
  13. // 初始化bean
  14. initFilterBean();

其中initFilterBean方法在两个位置起作用,一处是上文所述的init方法,另一处是afterPropertiesSet方法,在调用该方法前,需要保证用于Filter的所有的bean都已被设置,该方法由子类实现。

GenericFilterBean中包含一个内部私有类FilterConfigPropertyValues,主要用于将web.xml中定义的init-param的值取出。

OncePerRequestFilter

抽象类oncePerRequestFilter继承自GenericFilterBean,它保留了GenericFilterBean中的所有方法并对之进行了扩展,在oncePerRequestFilter中的主要方法是doFilter,代码如下:

  1. /**
  2. * This <code>doFilter</code> implementation stores a request attribute for
  3. * "already filtered", proceeding without filtering again if the
  4. * attribute is already there.
  5. * @see #getAlreadyFilteredAttributeName
  6. * @see #shouldNotFilter
  7. * @see #doFilterInternal
  8. */
  9. public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
  10. throws ServletException, IOException {
  11. if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
  12. throw new ServletException("OncePerRequestFilter just supports HTTP requests");
  13. }
  14. HttpServletRequest httpRequest = (HttpServletRequest) request;
  15. HttpServletResponse httpResponse = (HttpServletResponse) response;
  16. // 调用GenericFilterBean的getFilterName方法返回已过滤的属性名
  17. String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
  18. if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {
  19. // 未调用该过滤器或已过滤
  20. filterChain.doFilter(request, response);
  21. }
  22. else {
  23. // 进行过滤
  24. request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
  25. try {
  26. doFilterInternal(httpRequest, httpResponse, filterChain);
  27. }
  28. finally {
  29. // Remove the "already filtered" request attribute for this request.
  30. request.removeAttribute(alreadyFilteredAttributeName);
  31. }
  32. }
  33. }

在doFilter方法中,doFilterInternal方法由子类实现,主要作用是规定过滤的具体方法。

AbstractRequestLoggingFilter

AbstractRequestLoggingFilter继承了OncePerRequestFilter并实现了其doFilterInternal方法,该方法代码如下:

  1. /**
  2. * Forwards the request to the next filter in the chain and delegates down to the subclasses to perform the actual
  3. * request logging both before and after the request is processed.
  4. *
  5. * @see #beforeRequest
  6. * @see #afterRequest
  7. */
  8. @Override
  9. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
  10. throws ServletException, IOException {
  11. if (isIncludePayload()) {
  12. // 若日志中包含负载,则重置request
  13. request = new RequestCachingRequestWrapper(request);
  14. }
  15. // 过滤前执行的方法
  16. beforeRequest(request, getBeforeMessage(request));
  17. try {
  18. // 执行过滤
  19. filterChain.doFilter(request, response);
  20. }
  21. finally {
  22. // 过滤后执行的方法
  23. afterRequest(request, getAfterMessage(request));
  24. }
  25. }

doFilter方法中的beforeRequest和afterRequest方法由子类实现,RequestCachingRequestWrapper为AbstractRequestLoggingFilter的内部内,主要作用是重置request。

区别

我们在使用过滤器时,通常没必要知道GenericFilterBean、OncePerRequestFilter和AbstractRequestLoggingFilter,但不防碍我们了解这几个类,就上文所述,AbstractRequestLoggingFilter继承自OncePerRequestFilter,OncePerRequestFilter继承自GenericFilterBean,所以我们知道,genericFilterBean是任何类型的过滤器的一个比较方便的超类,这个类主要实现的就是从web.xml文件中取得init-param中设定的值,然后对Filter进行初始化(当然,其子类可以覆盖init方法)。

OncePerRequestFilter继承自GenericFilterBean,那么它自然知道怎么去获取配置文件中的属性及其值,所以其重点不在于取值,而在于确保在接收到一个request后,每个filter只执行一次,它的子类只需要关注Filter的具体实现即doFilterInternal。

AbstractRequestLoggingFilter是对OncePerRequestFilter的扩展,它除了遗传了其父类及祖先类的所有功能外,还在doFilterInternal中决定了在过滤之前和之后执行的事件,它的子类关注的是beforeRequest和afterRequest。

总体来说,这三个类分别执行了Filter的某部分功能,当然,具体如何执行由它们的子类规定,若你需要实现自己的过滤器,也可以根据上文所述继承你所需要的类。

spring 过滤器的更多相关文章

  1. spring 过滤器简介

    spring 过滤器简介 过滤器放在容器结构的什么位置 过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet.一个Jsp页面,甚至是一个HTML页面)之前截获进入的请 ...

  2. spring过滤器

    什么是过滤器 Spring 中不能处理用户请求,但可以用来提供过滤作用的一种Servlet规范.在请求进入容器之后,还未进入Servlet之前进行预处理,并且在请求结束返回给前端这之间进行后期处理.具 ...

  3. Spring过滤器组件自动扫描

    在这个Spring自动组件扫描的教程,您已经了解如何使Spring自动扫描您的组件.在这篇文章中,我们将展示如何使用组件过滤器自动扫描过程. 1.过滤组件 - 包含 参见下面的例子中使用Spring  ...

  4. spring过滤器和拦截器的区别和联系

    一 简介 (1)过滤器: 依赖于servlet容器,是JavaEE标准,是在请求进入容器之后,还未进入Servlet之前进行预处理,并且在请求结束返回给前端这之间进行后期处理.在实现上基于函数回调,可 ...

  5. spring过滤器篇

    CharacterEncodingFilter spring的web包下的一个过滤器,用于设置程序的字符编码,它有两个参数encoding和forceEncoding. encoding:字符集,将过 ...

  6. spring:过滤器和拦截器

    过滤器:网络通信模型的会话层控制: 拦截器:事务处理的aop注入(生命周期监控). 对于Servlet Filter,官方文档中说的很好, 并且给出了常见的应用场景. A filter is an o ...

  7. spring 过滤器- 过滤登陆请求路径(过滤静态资源跳转到登陆页面)

    public class LoginedFilter implements Filter { /** * 排除的地址 */ private Map<String, Boolean> ign ...

  8. Spring字符集过滤器CharacterEncodingFilter

    Spring中的字符集过滤器可以很方便的为我们解决项目中出现的中文乱码问题,而且使用方法也很简单,只需要在web.xml文件中配置一下该过滤器,设置两个重要的参数(encoding和forceEnco ...

  9. Spring 配置请求过滤器,编码格式设为UTF-8,避免中文乱码

    <!-- 配置请求过滤器,编码格式设为UTF-8,避免中文乱码--> <filter> <filter-name>springUtf8Encoding</fi ...

随机推荐

  1. iOS 播放远程网络音乐的核心技术点

    一.前言 这两天做了个小项目涉及到了远程音乐播放,因为第一次做这种音乐项目,边查资料边做,其中涉及到主要技术点有: 如何播放远程网络音乐 如何切换当前正在播放中的音乐资源 如何监听音乐播放的各种状态( ...

  2. Linux下Setuid命令! 转载

    Linux下Setuid命令! 转载  在Linux系统中每个普通用户都可以更改自己的密码,这是合理的设置. 问题是:用户的信息保存在文件/etc/passwd中,用户的密码保存在文件/etc/sha ...

  3. HDU 1710 Binary Tree Traversals (二叉树遍历)

    Binary Tree Traversals Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O ...

  4. 【Hibernate】浅析hibernate中的延迟加载

    1 简介 在使用一些查询方法时,方法执行了,但是并没有立刻发送SQL语句查询数据库.而是在访问对象的getXxx方法时候才触发SQL执行加载对象数据.这种机制就称为延迟加载. 2 优点 延迟加载主要是 ...

  5. 在iOS开发的Quartz2D使用中实现图片剪切和截屏功能

    原文  http://www.jb51.net/article/75671.htm 图片剪切一.使用Quartz2D完成图片剪切1.把图片显示在自定义的view中先把图片绘制到view上.按照原始大小 ...

  6. Git 撤消操作(分布式版本控制系统)

    1.覆盖提交 有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了.此时,可以运行带有 --amend 选项的提交命令尝试重新提交. $ git commit --amend 或 # g ...

  7. 【Algorithm】自底向上的归并排序

    一. 算法描述 自底向上的归并排序:归并排序主要是完成将若干个有序子序列合并成一个完整的有序子序列:自底向上的排序是归并排序的一种实现方式,将一个无序的N长数组切个成N个有序子序列,然后再两两合并,然 ...

  8. github上完成个人的站点搭建

    未完待续 很早就想有一个自己的站点了,可是我买不起服务器,不想研究WordPress,ect.无意间,博主发现了github居然可以实现自己梦想,加之网络上的资料偏旧(或则说github+jekyll ...

  9. PHP中的$_SERVER超全局变量

    详细参数 PHP编程中经常需要用到一些服务器的一些资料,特把$_SERVER的详细参数整理下,方便以后使用. $_SERVER['PHP_SELF'] #当前正在执行脚本的文件名,与 document ...

  10. 带你开始进入NPM的世界之NPM包的开发

    个人开发包的目录结构 ├── coverage //istanbul测试覆盖率生成的文件 ├── index.js //入口文件 ├── introduce.md //说明文件 ├── lib │   ...