拦截器与过滤器的区别

拦截器与过滤器的区别

底层思想是什么?

拦截器与过滤器都是基于AOP面向切面编程的思想来实现的。

两者有什么相同,有什么不同?

相同点:都可以对请求做出统一的处理,例如在方法调用前进行一些操作,在方法调后后处理一些操作

不同点:

  1. 拦截器是Spring提供的(org.springframework.web.servlet.HandlerInterceptor),而过滤器是Servlet提供的(java.servlet.*
  2. 触发时机不同,过滤器在请求到达Servlet前被拦截开始执行,拦截器在到达Controller前被拦截开始执行
  3. 实现不同,过滤器基于方法回调实现,而拦截器是基于动态代理(底层反射)实现
  4. 支持的项目不同,过滤器只能在Web项目中用,拦截器可以在Swing,Application中都能用
  5. 使用场景不同,因为拦截器更接近业务系统,所以拦截器主要用来实现项目中的业务判断的,比如:登录判断、权限判断、日志记录等业务。而过滤器通常是用来实现通用功能过滤的,比如:敏感词过滤、字符集编码设置、响应数据压缩等功能。

为什么使用他们?

​ 在我们的日常业务中,我们总有一些通用但又不涉及核心业务的需求,比如日志管理,权限管理,敏感信息排查等,如何将这部分内容抽取出来,而不侵入核心代码,并可以做到灵活的扩展。就可以使用拦截器或者过滤器,但他们应用场景是不同的。

FIlter

如何进行使用?

@Component
@WebFilter(urlPatterns = "/*")
public class filter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器:执行 init 方法。");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器:开始执行 doFilter 方法。");
        // 请求放行
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("过滤器:结束执行 doFilter 方法。");
    }

    @Override
    public void destroy() {
        System.out.println("过滤器:执行 destroy 方法。");
    }
}

生命周期是怎么样的?

Filter有三个需要实现的方法:init,doFilter,destroy

​ 当Web服务启动时,就会调用 init 方法,

​ 当请求进入时,在进入Controller之前就会被 doFilter 拦截到,然后判断是否后面还有拦截器,如果没有了,则执行业务方法,执行完业务方法,返回后,会回到 doFilter方法,再进行其他操作。这里需要注意:当最后一个Filter的 filterChain.doFilter(servletRequest, servletResponse); 被调用完后,数据已经被渲染到页面了,然后才操作的下面的处理。

​ Web服务结束时,destroy() 被调用。

如何控制Filter的拦截顺序,以及doFilter() 方法先后是如何执行的?

方法1:在web.xml中控制filter-mapping的位置来控制的,放在上面的会比放在下面的先执行,如下“用户登录检查过滤器”会比“接口日志过滤器”先执行

	<!-- 用户登录检测过滤器 -->
		<filter>
		 <filter-name>UserLoginFilter</filter-name>
			 <filter-class>net.tfgzs.demo.filter.UserLoginFilter</filter-class>
		</filter>
		<filter-mapping>
			 <filter-name>UserLoginFilter</filter-name>
			 <url-pattern>/*</url-pattern>
		</filter-mapping>
		<!--接口日志过滤器-->
	<filter>
		<filter-name>ApiLog</filter-name>
		<filter-class>net.tfgzs.demo.filter.ApiLog</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>ApiLog</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

方法2:在@WebFilter中并未找到排序的方法,可以通过Filter的文件名来控制,比如:

  1. 在同一个包下,aFilter > bFilter
  2. 在不同包下,a/a.Filter > a/b.Filter > b/a.Filter

当请求经过多个Filter时,在操作filterChain.doFilter(servletRequest, servletResponse);前后调用的顺序

image-20221124161334593

这里需注意:在最后一个Filter的doFilter的filterChain.doFilter(servletRequest, servletResponse);调用完后数据就返回页面了,然后才开始操作后面的操作。

Interceptor

如何使用?

@Component
public class Interceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("[ Interceptor ]:执行 preHandle 方法。");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("[ Interceptor ]:执行 postHandle 方法。");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("[ Interceptor ]:执行 afterCompletion 方法。");
    }
}
@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Autowired
    private Interceptor interceptor;
    @Autowired
    private Interceptor1 interceptor1;
    @Autowired
    private Interceptor2 interceptor2;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor)
                .addPathPatterns("/*");
        registry.addInterceptor(interceptor1)
                .addPathPatterns("/*");
        registry.addInterceptor(interceptor2)
                .addPathPatterns("/*");
    }
}

生命周期

​ 和Filter 是类似的,先顺序执行preHandle,再逆序执行postHandle,所有执行完后,逆序执行afterCompletion方法。

​ 这里注意:最后一个preHandle处理完后,开始执行业务,在执行postHandler前, 页面就已经被渲染了。也就是Controller返回数据后执行:this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);

如何控制拦截器的执行顺序

​ 在WebMvcConfigurer配置类中,按照注册的顺序执行。

总结

  1. 当同时使用拦截器与过滤器时,请求模型:

image-20221124165341727

  1. 代码中的执行顺序:
// web服务启动
[ Filter ]:执行 init 方法。
[ Filter ]1:执行 init 方法。
[ Filter ]2:执行 init 方法。

// 请求进入
[ Filter ]:开始执行 doFilter 方法。
[ Filter ]1:开始执行 doFilter 方法。
[ Filter ]2:开始执行 doFilter 方法。

[ Interceptor ]:执行 preHandle 方法。
[ Interceptor ]1:执行 preHandle 方法。
[ Interceptor ]2:执行 preHandle 方法。

[ Interceptor ]2:执行 postHandle 方法。
[ Interceptor ]1:执行 postHandle 方法。
[ Interceptor ]:执行 postHandle 方法。

[ Interceptor ]2:执行 afterCompletion 方法。
[ Interceptor ]1:执行 afterCompletion 方法。
[ Interceptor ]:执行 afterCompletion 方法。

[ Filter ]2:结束执行 doFilter 方法。
[ Filter ]1:结束执行 doFilter 方法。
[ Filter ]:结束执行 doFilter 方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值