前言
Filiter&Interceptor是Java开发中两大“拦截”技术,可以对资源请求进行预处理和后处理,通常用于资源访问的限制,前者是JavaEE的一部分,后者是Spring框架的一部分。
Filiter过滤器
Filiter QuickStart
要实现Filiter功能,要完成以下两件事:
- 创建一个类,这个类实现Filiter接口
- 为这个类加上
WebFiliter注解,配置资源拦截路径
@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 )
public class DemoFilter implements Filter {
//初始化方法, web服务器启动, 创建Filter实例时调用, 只调用一次
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init ...");
}
//拦截到请求时,调用该方法,可以调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
System.out.println("拦截到了请求 方法开始..."); //放行前业务逻辑
chain.doFilter(request, response); //放行请求
System.out.println("拦截到了请求 方法结束..."); //放行后业务逻辑
}
//销毁方法, web服务器关闭时调用, 只调用一次
public void destroy() {
System.out.println("destroy ... ");
}
}如果我们在SpringBoot项目中要使用Filiter,需要在SpringBoot启动类中加入@ServletComponentScan注解,这样Springboot才能支持Serverlet组件。
Filiter核心详解
当一个HTTP请求到达Serverlet容器的时候,容器就会根据Filiter注解来找到所有需要处理这个请求的Filiter,并创建一个FiliterChain对象,这个对象中包含了一个匹配请求的Filiter链表,链表的末尾是目标请求的真实方法,当真实方法完成后,沿链表逆向返回,最终回到客户端。Filiter的实质是函数回调。当Filiter有多个匹配时,Filiter的执行顺序是由过滤器的类名自然排序的。
Filiter在Web应用启动时执行init方法,在Web应用关闭时执行destroy方法,在拦截到请求时执行doFiliter方法。
Interceptor拦截器
Interceptor QuickStart
要实现Interceptor,我们要做两件事
- 创建一个配置类,定义拦截器的拦截路径
- 创建一个类,实现HandlerInterceptor接口,并重写其所有方法。
//自定义拦截器
@Component
public class DemoInterceptor implements HandlerInterceptor {
//目标资源方法执行前执行。 返回true:放行 返回false:不放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle .... ");
return true; //true表示放行
}
//目标资源方法执行后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ... ");
}
//视图渲染完毕后执行,最后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion .... ");
}
}@Configuration
public class WebConfig implements WebMvcConfigurer {
//自定义的拦截器对象
@Autowired
private DemoInterceptor demoInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册自定义拦截器对象
registry.addInterceptor(demoInterceptor).addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)
}
}Interceptor核心概念
Interceptor是Spring MVC中的一套机制,基于java反射机制实现。拦截发生在DispatcherServlet内部,DispatcherServlet是Spirng为Web环境提供的一个Serverlet容器,所有请求都会先经过它,通过 HandlerMapping 找到处理该请求的 Handler(一般是我们定义的Controller),以及匹配的Interceptor,封装到一个HandlerExecutionChain类中,然后DispatcherServlet开始执行这个链。
具体路径为:preHandleA->return true;放行->Controller方法->postHandleA->afterCompletionA
当存在多个拦截器时,执行顺序按照注册拦截器时的顺序执行(addInterceptor),如果拦截器类中存在@Order(NUM)注解,NUM越小的拦截器将越在前面执行。
Filite&Interceptor&AOP 三者区别
| 特性 | Filter (过滤器) | Interceptor (拦截器) | AOP (面向切面编程) |
|---|---|---|---|
| 提供方 | Java Servlet规范 | Spring MVC框架 | Spring框架 (AOP思想的实现) |
| 依赖关系 | 独立于Spring,仅依赖Servlet容器 | 依赖Spring MVC容器 | 依赖Spring IoC容器 |
| 作用范围 | Servlet容器级别,所有HTTP请求 | Spring MVC框架级别,仅限Controller请求 | Spring容器级别,任何Bean的方法 |
| 拦截粒度 | URL级别(粗粒度) | Controller/Handler级别(中等粒度) | 方法/异常等任意连接点(细粒度) |
| 访问能力 | 可访问原始的HttpServletRequest和HttpServletResponse |
可访问Handler、ModelAndView,可注入Spring Bean |
可访问方法参数、返回值、异常对象,可注入Spring Bean |
| 能否修改请求 | 可以修改请求和响应对象 | 不能直接修改请求体,但可以影响ModelAndView |
可以通过环绕通知修改参数、返回值或阻止方法执行 |
| 执行顺序 | 在Interceptor之前执行 | 在Filter之后,AOP之前(针对Controller方法) | 在Interceptor之后(针对Controller方法),包裹具体方法 |