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项目基本都是前后端分离的,不可避免地要解决跨域问题。看Filter接口继承图,发现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源码阅读:过滤器相关推荐

  1. SpringMVC源码阅读系列汇总

    1.前言 1.1 导入 SpringMVC是基于Servlet和Spring框架设计的Web框架,做JavaWeb的同学应该都知道 本文基于Spring4.3.7源码分析,(不要被图片欺骗了,手动滑稽 ...

  2. springmvc源码阅读3--dispatcherServlet reqeust的执行流程

    一.前言 太多的时候总是会遇到群里面问,报404怎么肥事呀,前台的参数怎么后台收不到呀--,上次就在群里面遇到过,围绕这一个点:input的name值是不是错了呀,人家妹子都截了好几次图说没有问题,然 ...

  3. SpringMVC源码阅读(一)

    DispatcherServlet是整个SpringMVC初始化和处理请求的重要类,作为一个servlet,拥有 public void init(ServletConfig config) thro ...

  4. SpringMVC源码阅读(三)

    先理一下Bean的初始化路线 org.springframework.beans.factory.support.AbstractBeanDefinitionReader public int loa ...

  5. Nginx模块开发:模块结构的源码阅读以及过滤器(Filter)模块的实现

    Nginx模块开发:模块结构的源码阅读以及过滤器(Filter)模块的实现 一.Nignx中的模块是什么? 二.模块的基本结构 `ngx_module_s` `ngx_command_s` `ngx_ ...

  6. log4j源码阅读(一)之Logger

    概述 log4j是一款非常方便而且强大的开源日志项目,在经过简单的配置后,可以达到相当不错的效果. 头脑一热决定对log4j的源码进行一定的阅读,其初衷是希望通过源码的阅读,提高写代码的能力. log ...

  7. springMvc源码刨析笔记

    springMvc源码刨析笔记 MVC 全名是 Model View Controller,是 模型(model)-视图(view)-控制器(controller) 的缩写, 是⼀种⽤于设计创建 We ...

  8. Rpc框架dubbo-client(v2.6.3) 源码阅读(二)

    接上一篇 dubbo-server 之后,再来看一下 dubbo-client 是如何工作的. dubbo提供者服务示例, 其结构是这样的! dubbo://192.168.11.6:20880/co ...

  9. SpringMVC源码分析系列[转]

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

最新文章

  1. 机器学习中防止过拟合的处理方法
  2. Premiere Pro CS4软件安装教程
  3. P3959-宝藏【模拟退火】
  4. c语言 at指令,学渣求指教,如何识别字符串中的AT命令并逐个输出,求程序!!!...
  5. Spring boot整合shiro权限管理
  6. Python3中queue模块的使用
  7. 如何将多个Excel合并到一个Excel中?
  8. php编写一个学生类_0063 PHP编程编写学生分数信息编辑和删除功能网页
  9. 新版微信Wechart添加多个运营者(管理员)
  10. 浅析欢乐时光(HAPPY TIME)病毒 (转)
  11. 如何实现必须关注公众号才能使用微信小程序,从而通过微信小程序免费为公众号吸粉。#微信营销#微信公众号吸粉#微信小程序吸粉
  12. 安卓电子书格式_在安卓上比较适合看英文电子书的软件
  13. 关于电源线 USB台灯3C认证相关介绍
  14. ALSA子系统(十四)------snd_pcm_drain和snd_pcm_drop
  15. PHP获取客户端真实 IP 地址
  16. umi.js的简单理解
  17. 用 C 语言开发一门编程语言 — 字符串的设计与实现
  18. iOS7人机界面指南 – ISUX原创翻译
  19. 安卓 root权限笔记
  20. BLDC电机是如何旋转的?

热门文章

  1. 关于Oracle full outer join 的bug问题分析及处理
  2. 2010年暑假送给大学生30句话
  3. 基于JQuery实现的幻灯片轮播(对时间间隔做严格控制)
  4. IOS和Andriod手机浏览器内核
  5. 「NOI2017」泳池
  6. ansible基础-playbooks
  7. linux 下 用户与用户组
  8. 软件构架实践(第2版)学习笔记
  9. 使用GPS实时记录运动路线
  10. 人工智能中对机器学非常简要的介绍