跳至主要內容
hint - 拦截器 vs 过滤器

拦截器 vs 过滤器

拦截器(Interceptor)和过滤器(Filter)都是 Java Web 应用中实现 AOP(面向切面编程)思想的重要组件,它们都可以用来在请求处理前后执行特定的逻辑。但在底层机制、归属规范和应用场景上有非常显著的区别。

在以 Spring Boot 为核心的后端架构中,理解这两者的差异是设计优雅请求处理链路的关键。

核心对比

维度 过滤器 (Filter) 拦截器 (Interceptor)
规范与归属 Servlet 规范的一部分,由 Servlet 容器(如 Tomcat)管理。 Spring MVC 框架的一部分,由 Spring 容器管理。
触发机制 基于函数回调(chain.doFilter())。 基于 Java 反射机制(动态代理)和 Spring 的 HandlerExecutionChain
拦截范围 几乎拦截所有进入容器的请求(包括静态资源、JSP 等)。 通常只拦截发往 Controller(Handler)的请求。
上下文感知能力 只能获取到 ServletRequestServletResponse。感知不到 Spring 的 Bean 和具体的 Controller 方法。 可以注入 Spring Bean,并且能通过参数获取到即将执行的 Controller 方法(HandlerMethod)。
执行时机 在请求进入 DispatcherServlet 之前执行。 DispatcherServlet 之后,到达具体 Controller 之前执行。

codejava hint大约 4 分钟
hint - 请求从客户端发出的流程

整体流程

如果后端是 Spring Boot(常见是 Spring MVC + Tomcat),一个请求从客户端发出到后端处理完成,大致可以分成两层来看:

一、从网络角度看,请求是怎么到后端的

1. 客户端发起请求

客户端可能是:

  • 浏览器
  • App
  • 前端项目(Vue/React)
  • 其他服务

比如前端发一个请求:

POST /api/user/login HTTP/1.1
Host: example.com
Content-Type: application/json

{"username":"zs","password":"123456"}

codejava hint大约 4 分钟
hint - 注解理解2

注解

什么是注解 @interface

注解就是一个继承了 java.lang.annotation.Annotation 的接口, 而对应的值实际上会被编译成对应的抽象方法

测试

// Penguin.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Penguin {
    String value() default "";
}

codejava hint大约 5 分钟
hint - 注解理解3

注解3

自定义注解流程

自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Penguin {
    String value() default "";
}

codejava hint大约 3 分钟
hint - 屏障

屏障

屏障 = 在某个操作前后插入的"检查点"或"钩子"

想象一个小区门禁:

居民进出 → [门禁屏障] → 记录谁进出了 → 放行

屏障不做"拦截",只做"记录"或"检查"

计算机中的屏障

内存屏障

CPU 为了性能会重排序指令,内存屏障告诉 CPU:

指令1
指令2
[内存屏障] ←  barrier 之前的指令必须先执行完
指令3
指令4

codejava hint大约 1 分钟
hint - i++与++i

i++ 对应的 Java 字节码指令主要取决于 变量 i 的类型(是局部变量还是成员变量)以及 它在代码中的使用方式(是单独作为语句还是作为表达式的一部分)

1. 局部变量

i 是方法内的局部 int 变量时,Java 编译器会使用专门的指令 iinc 进行优化。

情况 A:单独语句 (i++;)

如果只是单纯的自增,不涉及赋值给其他变量:


codejava hint大约 4 分钟
hint - 跨域
alt text
alt text

简单请求(simple request)确实是“发出去了”,服务器也能收到、处理并返回结果,但浏览器在收到响应后,会因为安全策略而“拦截”掉结果,不让前端 JavaScript 访问它。

alt text

codejava hint小于 1 分钟
hint - AOP

操作

AOP可以用来实现公共字段填充

1). 自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法

2). 自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值

3). 在 Mapper 的方法上加入 AutoFill 注解

在定义切面时,有两步:

  1. 定义切点(Pointcut):告诉 AOP —— 哪些方法需要被拦截;

  2. 定义通知(Advice):告诉 AOP —— 拦截到后要做什么。


codejava hint小于 1 分钟
hint - 注解理解

首先,注解的使用分成两类

  • 编译期生效(Lombok:改写字节码,帮你生成方法)
  • 运行期生效(Spring:反射 + AOP,帮你注入 Bean、加事务、AoP等)

个人目前感觉

注解就是一个标记,在代码编译或者运行时可以通过一些手段找到对应标记的东西

然后基于此,相当于打了个坐标,然后在此上面进行一些自己的处理

主要就是定义注解,然后使用注解,最后写个注解处理器来捕获并处理

alt text

codejava hint小于 1 分钟
hint - List初始化

带初始值的初始化

  • 如果是 java 9+, 可以直接使用 list.of

    List<String> list = List.of("a", "b", "c");
    
    List<String> list = List.of(
      new Student("aaa",1),
      new Student("bbb",2),
      new Student("ccc",3),
    );
    

    这种方式创建的列表 不可修改,add()remove() 都会抛出 UnsupportedOperationException

  • 但如果是 java 8,就没有这个,可以使用 Stream

      List<Student> list1 = Stream.of(
          new Student("Alice", 20),
          new Student("Bob", 21),
          new Student("Charlie", 22)
      ).collect(Collectors.toList());
    

codejava hint小于 1 分钟