过滤器 与 拦截器

文章目录

过滤器 与 拦截器

一、过滤器(Filter)

1、特点

过滤器是基于Java Servlet规范的一部分,用于在请求 到达Servlet之前 或 响应离开Servlet之后 对请求和响应进行处理。

  • 过滤器可以对所有请求进行处理,不仅限于特定的Servlet或Spring MVC控制器。
  • 过滤器在Servlet容器层面工作,而不是Spring层面。
  • 适合用于日志记录、身份验证、权限检查等通用功能。

2、生命周期

java 复制代码
public interface Filter {
    // 初始化方法
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    // 执行拦截方法
    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    // 销毁方法
    default void destroy() {
    }
}
markdown 复制代码
# 创建【init方法】
1. 特点:
		服务器启动,项目加载,创建filter对象,执行【init方法】(只执行一次)
2. 对比Servlet:
		先于Servlet的init方法执行

# 拦截【doFilter方法】
1. 特点:
		用户访问被拦截的目标资源时,执行【doFilter方法】(浏览器每访问一次,就会执行一次)
2. 对比Servlet:
		先于Servlet的service方法执行

# 销毁【destroy方法】
1. 特点:
		服务器关闭,项目关闭,销毁filter对象,执行【destroy方法】(只执行一次)
2. 对比Servlet:
		后于Servlet的destroy方法执行

3、实现

定义拦截器只要实现Filter接口,重写doFilter方法即可

java 复制代码
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 前置处理...
        System.out.println("Filter doFilter before");

        // 处理请求
        chain.doFilter(request, response);

        // 后置处理...
        System.out.println("Filter doFilter after");
    }
}

注册拦截器(SpringBoot示例)

java 复制代码
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<MyFilter> myFilter() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter());
        // 过滤路径(/*表示所有)
        registrationBean.addUrlPatterns("/*");
        // 过滤顺序(多个Filter按Order从小到大顺序执行)
        registrationBean.setOrder(1);
        return registrationBean;
    }
}

4、过滤器链

1)配置 order

多个 Filter 按 Order的大小 从小到大 执行(如果没有配置Order,按 Bean声明的顺序 从上到下 执行)

java 复制代码
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<MyFilter> myFilter1() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter1());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(1);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean<MyFilter> myFilter2() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter2());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(2);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean<MyFilter> myFilter3() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter3());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(3);
        return registrationBean;
    }
}

2)执行顺序

java 复制代码
Filter1 doFilter before
Filter2 doFilter before
Filter3 doFilter before

Servlet service

// 如果发生异常,就不会执行 doFilter after 了
Filter3 doFilter after
Filter2 doFilter after
Filter1 doFilter after

二、拦截器 Inteceptor

1、特点

拦截器是Spring MVC提供的功能,用于在请求到达控制器之前和响应离开控制器之后进行处理。

  • 拦截器主要用于Spring MVC层面,处理的是控制器层的请求和响应。
  • 适合用于权限检查、日志记录、请求计时等与业务逻辑密切相关的操作。

2、生命周期

java 复制代码
public interface HandlerInterceptor {
    // Controller执行之前调用
	default boolean preHandle(HttpServletRequest request,  HttpServletResponse response, Object handler) throws Exception {
		return true;
	}

    // Controller执行之后调用(发生异常 或 preHandle=false 不会调用)
	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
	}

    // Controller执行之后调用(发生异常也会调用,preHandle=false不会调用)
	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
	}
}

3、实现

自定义拦截器只要实现HandlerInterceptor接口,按需重写指定即可。

java 复制代码
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Pre Handle method is Called");
        return true; // 继续处理请求
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Post Handle method is Called");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Request and Response is completed");
    }
}

注册拦截器

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加自定义拦截器
        registry.addInterceptor(new MyInterceptor())
            	// 配置拦截路径
                .addPathPatterns("/**")
            	// 配置放过路径
                .excludePathPatterns();
    }
}

4、拦截器链

1)配置 order

多个 Interceptor 按 Order的大小 从小到大 执行(如果没有配置Order,按 添加的顺序 从上到下 执行)

java 复制代码
@Configuration
public class MyAdapter implements WebMvcConfigurer {
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**").order(1);
        registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**").order(2);
        registry.addInterceptor(new MyInterceptor3()).addPathPatterns("/**").order(3);
	}
}

2)执行顺序(没有异常)

java 复制代码
Interceptor1 preHandle	// true
Interceptor2 preHandle	// true
Interceptor3 preHandle	// true
    
Servlet service

Interceptor3 postHandle
Interceptor2 postHandle
Interceptor1 postHandle  

Interceptor3 afterCompletion
Interceptor2 afterCompletion
Interceptor1 afterCompletion

3)某拦截器 preHandle 返回false

这里我们假设中间的 Interceptor2 的 preHandle 返回 false

java 复制代码
Interceptor1 preHandle	// true
Interceptor2 preHandle	// false

Interceptor1 afterCompletion
properties 复制代码
之前的拦截器(即 Interceptor1): 执行了 preHandle 和 afterCompletion
阻隔的拦截器(即 Interceptor2): 执行了 preHandle
之后的拦截器(即 Interceptor3): 全部不执行

4)执行顺序(有异常)

java 复制代码
Interceptor1 preHandle	// true
Interceptor2 preHandle	// true
Interceptor3 preHandle	// true

// 发生异常之前
Servlet service

// 这个竟然是在 异常的堆栈信息 之前执行的
Interceptor3 afterCompletion
Interceptor2 afterCompletion
Interceptor1 afterCompletion

异常的堆栈信息

// 发生异常之后,又整体执行了一遍....
Interceptor1 preHandle
Interceptor2 preHandle
Interceptor3 preHandle

Interceptor3 postHandle
Interceptor2 postHandle
Interceptor1 postHandle

Interceptor3 afterCompletion
Interceptor2 afterCompletion
Interceptor1 afterCompletion

5)小结

整体顺序:所有 preHandle -> Controller -> 所有 postHandle -> 所有 afterCompletion

markdown 复制代码
# preHandle
1. 调用前提
		无
2. 调用时机
		Controller方法处理之前
3. 调用链顺序
		顺序执行:preHandle1 ==> preHandle2 ==> preHandle3

# postHandle
1. 调用前提
		preHandle返回true 且 Controller没有发生异常
2. 调用时机
		Controller方法处理完之后,afterCompletion调用之前
3. 调用链顺序
		倒序执行:postHandle3 ==> postHandle2 ==> postHandle1

# afterCompletion
1. 调用前提
		preHandle返回true(Controller发生异常也会调用)
2. 调用时机
		Controller方法处理完之后
3. 调用链顺序
		倒序执行:afterCompletion3 ==> afterCompletion2 ==> afterCompletion1

三、执行顺序

1、自定义 Servlet

java 复制代码
public class MyServlet extends HttpServlet {
    @Override
    public void destroy() {
        System.out.println("Servlet destroy");
        super.destroy();
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("Servlet init");
        super.init(config);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet service");
        resp.getWriter().write("Hello from MyServlet");
    }
}
java 复制代码
@Configuration
public class ServletConfig {
    @Bean
    public ServletRegistrationBean<MyServlet> myServlet() {
        return new ServletRegistrationBean<>(new MyServlet(), "/myServlet");
    }
}

2、自定义 Filter

java 复制代码
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter init");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 前置处理...
        System.out.println("Filter doFilter before");

        // 处理请求
        chain.doFilter(request, response);

        // 后置处理...
        System.out.println("Filter doFilter after");
    }

    @Override
    public void destroy() {
        System.out.println("Filter destroy");
        Filter.super.destroy();
    }
}
java 复制代码
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<MyFilter> myFilter() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(1);
        return registrationBean;
    }
}

3、自定义 Inteceptor

java 复制代码
public class MyInterceptor 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");
    }
}
java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns();
    }
}

4、对比:Servlet 与 Filter

java 复制代码
// 项目启动
Filter init
    
// 访问 http://localhost:8080/myServlet
Servlet init
Filter doFilter before
Servlet service
Filter doFilter after

// 项目关闭
Servlet destroy
Filter destroy

5、对比:Filter 与 Inteceptor

java 复制代码
@RestController
public class TestController {
    @GetMapping("/interceptor")
    public ResponseEntity<String> interceptor() {
        System.out.println("Servlet service");
        return ResponseEntity.ok("SUCCESS");
    }
}
java 复制代码
// 项目启动
Filter init

// 访问 http://localhost:8080/interceptor
Filter doFilter before
Interceptor preHandle
Servlet service
Interceptor postHandle
Interceptor afterCompletion
Filter doFilter after

// 项目关闭
Filter destroy

6、小结

java 复制代码
// 项目启动
Filter init

// 访问接口
Servlet init
Filter doFilter before
Interceptor preHandle
Servlet service
Interceptor postHandle
Interceptor afterCompletion
Filter doFilter after

// 项目关闭
Servlet destroy
Filter destroy
相关推荐
阿伟*rui2 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck4 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei4 小时前
java的类加载机制的学习
java·学习
Yaml45 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~5 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616886 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7896 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java6 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~7 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust