=Start=
缘由:
学习、理解一下Java Web的相关知识。
正文:
参考解答:
Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。不同的是:
- 使用范围不同:Filter是Servlet规范规定的,只能用于Web程序中。而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。
- 规范不同:Filter是在Servlet规范中定义的,是Servlet容器支持的。而拦截器是在Spring容器内的,是Spring框架支持的。
- 使用的资源不同:同其他的代码块一样,拦截器也是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过IoC注入到拦截器即可;而Filter则不能。
- 深度不同:Filter在只在Servlet前后起作用。而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。所以在Spring构架的程序中,要优先使用拦截器。
实际上Filter和Servlet极其相似,区别只是Filter不能直接对用户生成响应。实际上Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽取的通用代码,通过使用Filter可以实现更好的复用。
Spring的Interceptor(拦截器)与Servlet的Filter有相似之处,都能实现权限检查、日志记录等。不同的是:
Filter | Interceptor | Summary |
---|---|---|
Filter 接口定义在 javax.servlet 包中 | 接口 HandlerInterceptor 定义在org.springframework.web.servlet 包中。 | |
Filter 定义在 web.xml 中 | ||
Filter在只在 Servlet 前后起作用。Filters 通常将 请求和响应(request/response) 当做黑盒子,Filter 通常不考虑servlet 的实现。 | 拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户介入(hook into)请求的生命周期,在请求过程中获取信息,Interceptor 通常和请求更加耦合。 | 在Spring构架的程序中,要优先使用拦截器。几乎所有 Filter 能够做的事情,interceptor 都能够轻松的实现 |
Filter 是 Servlet 规范规定的。 | 而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。 | 使用范围不同 |
Filter 是在 Servlet 规范中定义的,是 Servlet 容器支持的。 | 而拦截器是在 Spring容器内的,是Spring框架支持的。 | 规范不同 |
Filter 不能够使用 Spring 容器资源 | 拦截器是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如 Service对象、数据源、事务管理等,通过IoC注入到拦截器即可。 | Spring 中使用 interceptor 更容易 |
Filter 是被 Server(like Tomcat) 调用 | Interceptor 是被 Spring 调用。 | 因此 Filter 总是优先于 Interceptor 执行 |
interceptor 使用
interceptor 的执行顺序大致为:
- 请求到达 DispatcherServlet
- DispatcherServlet 发送至 Interceptor ,执行 preHandle
- 请求达到 Controller
- 请求结束后,postHandle 执行
Spring 中主要通过 HandlerInterceptor 接口来实现请求的拦截,实现 HandlerInterceptor 接口需要实现下面三个方法:
- preHandle() – 在handler执行之前,返回 boolean 值,true 表示继续执行,false 为停止执行并返回。
- postHandle() – 在handler执行之后, 可以在返回之前对返回的结果进行修改
- afterCompletion() – 在请求完全结束后调用,可以用来统计请求耗时等等
统计请求耗时:
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class ExecuteTimeInterceptor extends HandlerInterceptorAdapter{ private static final Logger logger = Logger.getLogger(ExecuteTimeInterceptor.class); //before the actual handler will be executed public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { long startTime = System.currentTimeMillis(); request.setAttribute("startTime", startTime); return true; } //after the handler is executed public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { long startTime = (Long)request.getAttribute("startTime"); long endTime = System.currentTimeMillis(); long executeTime = endTime - startTime; //modified the exisitng modelAndView modelAndView.addObject("executeTime",executeTime); //log it if(logger.isDebugEnabled()){ logger.debug("[" + handler + "] executeTime : " + executeTime + "ms"); } } }
例子来源:mkyong
Filter 使用
Servlet 的 Filter 接口需要实现如下方法:
void init(FilterConfig paramFilterConfig)
– 当容器初始化 Filter 时调用,该方法在 Filter 的生命周期只会被调用一次,一般在该方法中初始化一些资源,FilterConfig 是容器提供给 Filter 的初始化参数,在该方法中可以抛出 ServletException 。init 方法必须执行成功,否则 Filter 可能不起作用,出现以下两种情况时,web 容器中 Filter 可能无效: 1)抛出 ServletException 2)超过 web 容器定义的执行时间。doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain)
– Web 容器每一次请求都会调用该方法。该方法将容器的请求和响应作为参数传递进来, FilterChain 用来调用下一个 Filter。void destroy()
– 当容器销毁 Filter 实例时调用该方法,可以在方法中销毁资源,该方法在 Filter 的生命周期只会被调用一次。FrequencyLimitFilter com.company.filter.FrequencyLimitFilter FrequencyLimitFilter /login/*
Filter 和 Interceptor 的一些用途
- Authentication Filters
- Logging and Auditing Filters
- Image conversion Filters
- Data compression Filters
- Encryption Filters
- Tokenizing Filters
- Filters that trigger resource access events
- XSL/T filters
- Mime-type chain Filter
Request Filters 可以:
- 执行安全检查 perform security checks
- 格式化请求头和主体 reformat request headers or bodies
- 审查或者记录日志 audit or log requests
- 根据请求内容授权或者限制用户访问 Authentication-Blocking requests based on user identity
- 根据请求频率限制用户访问
Response Filters 可以:
- 压缩响应内容,比如让下载的内容更小 Compress the response stream
- 追加或者修改响应 append or alter the response stream
- 创建或者整体修改响应 create a different response altogether
- 根据地方不同修改响应内容 Localization-Targeting the request and response to a particular locale
参考链接:
- http://einverne.github.io/post/2017/08/spring-interceptor-vs-filter.html
- https://gopalakrishnadurga.wordpress.com/2012/06/08/filter-vs-interceptor/
- https://stackoverflow.com/a/8006315/1820217
- Difference between Interceptor and Filter in Spring MVC
- Spring filter和拦截器(Interceptor)的区别和执行顺序
- springboot过滤器和拦截器的实现和区别
- springboot(五)filter/interceptor/listener
- Spring Boot中Filter的过滤顺序
=END=
《 “Spring Interceptor vs Filter 拦截器和过滤器区别” 》 有 11 条评论
浅析Spring AOP
https://mp.weixin.qq.com/s/hgML7LAuE04l6jwY6Ph0mQ
https://docs.spring.io/spring/docs/current/spring-framework-reference/#aop-introduction-defn
`
Aop(Aspect-OrientedProgramming)面向切面编程是对OOP的补充,专注于系统中不同模块统一的处理逻辑,比如事务管理,日志管理,缓存等系统级服务。
众所周知,SpringAop基于代理实现的,比如JDK动态代理和CGLIB代理。
那么如何使用JDK动态代理呢?
1):创建实现了InvocationHandler接口的类,实现invoke方法,该方法将在与之关联的代理类方法调用的时候执行
2):通过Proxy.newProxyInstance()方法返回代理对象
`
使用Spring框架实现远程服务暴露与调用
http://www.spring4all.com/article/963
Spring Boot 2.0(五):Docker Compose+Spring Boot+Nginx+Mysql 实践
https://mp.weixin.qq.com/s/PRM3XRV89bDTptsjs1v5yg
Spring AOP 模块概述
https://mp.weixin.qq.com/s/XkSpuDCrx3nWSOBhQqAm9g
Spring AOP实现原理
https://juejin.im/post/5af3bd6f518825673954bf22
AOP(面向切面编程)、Filter(过虑器)、Interceptor(拦截器)
https://blog.csdn.net/testcs_dn/article/details/80225584
Java三大器之拦截器(Interceptor)的实现原理及代码示例
https://blog.csdn.net/testcs_dn/article/details/80263568
Java三大器之过滤器(Filter)的工作原理和代码演示
https://blog.csdn.net/testcs_dn/article/details/80263691
Java三大器之监听器(Listener)的工作原理和代码演示
https://blog.csdn.net/testcs_dn/article/details/80263718
Springboot 系列(六)web 开发之拦截器和三大组件
https://www.codingme.net/2019/02/springboot/springboot-06-web-filter-apo-webbase/
怎么回答面试官:你对Spring的理解?
https://www.zhihu.com/question/48427693/answer/691483076
10分钟详解Spring全家桶7大知识点
https://zhuanlan.zhihu.com/p/59327709
程序员,你还不会合理选择Filter、Interceptor、Aspect?
https://juejin.im/post/5d64f867f265da03cf7a9d15
`
# Filter过滤器
过滤器可以拦截到方法的请求和响应(ServletRequest request, ServletResponse response),并对请求响应做出过滤操作。
过滤器依赖于servlet容器。在实现上,基于函数回调,它可以对几乎所有请求进行过滤,一个过滤器实例只能在容器初始化时调用一次。
使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
# Interceptor拦截器
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上,基于Java的反射机制,属于面向切面编程(AOP)的一种运用,就是在一个方法前,调用一个方法,或者在方法后,调用一个方法。
# Aspect切片
AOP操作可以对操作进行横向的拦截,最大的优势在于他可以获取执行方法的参数,对方法进行统一的处理。常见使用日志,事务,请求参数安全验证等。
# 总结
如果三者方式同时采用,那他们的执行顺序是什么呢?
filter -> interceptor -> ControllerAdvice -> aspect -> controller
返回值顺序,或异常返回顺序
controller -> aspect -> controllerAdvice -> Interceptor -> Filter
`
原创干货 | 过滤器设计缺陷导致权限绕过
https://mp.weixin.qq.com/s/Cotu3613adQNklEgE9q_YA
`
修复建议及防御,以Java为例:
(1)使用如下方法进行相关路径的获取:
request.getServletPath()+(request.getPathInfo()== null? “”: request.getPathInfo());
(2)对相关接口访问进行标准化处理,剔除不相关的元素,例如…/,分隔符(;)后的内容等;
这里推荐使用ESAPI的canonicalize方法进行集成,对相关输入进行规范化处理,样例代码如下:
ESAPI.encoder().canonicalize(URI)
同时在对应的配置文件ESAPI.properties禁用双重uri编码(默认开启):
Encoder.AllowMultipleEncoding=false
(3)尽量不要使用类似startsWith()、endsWith()进行判断;
(4)使用成熟的权限控制框架进行权限校验。(SpringSecurity、Shiro等)
`
[…] SPRING INTERCEPTOR VS FILTER 拦截器和过滤器区别 […]
如何优雅地记录操作日志?
https://mp.weixin.qq.com/s/JC51S_bI02npm4CE5NEEow
`
操作日志几乎存在于每个系统中,而这些系统都有记录操作日志的一套 API。操作日志和系统日志不一样,操作日志必须要做到简单易懂。所以如何让操作日志不跟业务逻辑耦合,如何让操作日志的内容易于理解,如何让操作日志的接入更加简单?上面这些都是本文要回答的问题。我们主要围绕着如何“优雅”地记录操作日志展开描述,希望对从事相关工作的同学能够有所帮助或者启发。
1. 操作日志的使用场景
2. 实现方式
2.1 使用 Canal 监听数据库记录操作日志
2.2 通过日志文件的方式记录
2.3 通过 LogUtil 的方式记录日志
2.4 方法注解实现操作日志
3. 优雅地支持 AOP 生成动态的操作日志
3.1 动态模板
4. 代码实现解析
4.1 代码结构
4.2 模块介绍
5. 总结
`