当前位置: 代码网 > it编程>编程语言>Java > SpringBoot中请求处理组件全面对比与选型指南

SpringBoot中请求处理组件全面对比与选型指南

2026年07月24日 Java 我要评论
spring boot 提供了多种组件来处理请求的不同阶段:过滤器、拦截器、aop、监听器、controlleradvice、参数/返回值处理器。它们功能上有重叠但各有定位,初学者容易混淆。本文系统讲

spring boot 提供了多种组件来处理请求的不同阶段:过滤器、拦截器、aop、监听器、controlleradvice、参数/返回值处理器。它们功能上有重叠但各有定位,初学者容易混淆。本文系统讲解每种组件的原理、用法,并从执行顺序、适用场景、功能交叉点等维度进行横向对比,帮助在不同场景下做出正确选型。

一、整体架构与执行流程

1.1 请求处理全链路

一个 http 请求到达 spring boot 应用后,会依次经过以下组件:

http 请求
    |
    v
┌─────────────────────────────────────────────────────────┐
│  servlet 容器(tomcat)                                  │
│    ↓                                                    │
│  filter(过滤器)─── 可拦截请求和响应                     │
│    ↓                                                    │
│  dispatcherservlet                                      │
│    ├──→ handlerinterceptor.prehandle()(拦截器-前置)    │
│    ├──→ handlermethodargumentresolver(参数处理器)      │
│    ├──→ controller 方法(被 aop 环绕)                   │
│    │     └──→ aop @before / @around                     │
│    ├──→ handlermethodreturnvaluehandler(返回值处理器)  │
│    ├──→ handlerinterceptor.posthandle()(拦截器-后置)   │
│    └──→ handlerinterceptor.aftercompletion()(拦截器-完成)│
│                                                         │
│  异常分支:                                               │
│    任何阶段抛出异常 → @restcontrolleradvice 捕获          │
│                                                         │
│  事件分支:                                               │
│    servletrequestlistener / applicationevent 贯穿全程    │
└─────────────────────────────────────────────────────────┘
    |
    v
http 响应

1.2 六大组件定位

组件所属层级核心职责一句话定位
filterservlet 容器请求/响应的过滤与包装最外层的守门员
interceptorspring mvccontroller 前后拦截controller 的贴身保镖
aopspring 容器方法级别的横切逻辑任意 bean 方法的拦截器
listenerservlet / spring事件监听与回调全局事件的观察者
controlleradvicespring mvc全局异常处理与数据绑定controller 的后勤保障
argumentresolverspring mvc自定义参数解析请求参数 → controller 入参
returnvaluehandlerspring mvc自定义返回值处理controller 返回值 → 响应

二、filter(过滤器)

2.1 原理

filter 是 servlet 规范的一部分,运行在 dispatcherservlet 之前和之后,可以拦截所有 http 请求(包括静态资源)。

请求 → filterchain
         filter1.dofilter()
           filter2.dofilter()
             dispatcherservlet
           filter2(响应)
         filter1(响应)
       响应

2.2 用法

import jakarta.servlet.*;
import jakarta.servlet.http.httpservletrequest;
import jakarta.servlet.http.httpservletresponse;
import org.springframework.core.annotation.order;
import org.springframework.stereotype.component;

import java.io.ioexception;

/**
 * 请求日志过滤器
 */
@component
@order(1)
public class requestlogfilter implements filter {

    @override
    public void dofilter(servletrequest request, servletresponse response,
                         filterchain chain) throws ioexception, servletexception {
        httpservletrequest req = (httpservletrequest) request;
        httpservletresponse resp = (httpservletresponse) response;

        long start = system.currenttimemillis();
        system.out.println("[filter] 请求进入: " + req.getmethod() + " " + req.getrequesturi());

        // 放行到下一个 filter 或 dispatcherservlet
        chain.dofilter(request, response);

        long cost = system.currenttimemillis() - start;
        system.out.println("[filter] 请求完成: " + req.getrequesturi() + " 耗时 " + cost + "ms 状态码 " + resp.getstatus());
    }
}

也可以通过 filterregistrationbean 注册:

import org.springframework.boot.web.servlet.filterregistrationbean;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;

@configuration
public class filterconfig {

    @bean
    public filterregistrationbean<requestlogfilter> requestlogfilter() {
        filterregistrationbean<requestlogfilter> bean = new filterregistrationbean<>();
        bean.setfilter(new requestlogfilter());
        bean.addurlpatterns("/*");
        bean.setorder(1);
        bean.setname("requestlogfilter");
        return bean;
    }
}

2.3 特点

特点说明
拦截范围所有请求(包括静态资源、非 controller 请求)
能否访问 spring bean可以(通过注入)
能否获取 controller 信息不能(不知道哪个 controller 处理)
能否修改请求/响应体可以(通过包装 httpservletrequestwrapper
执行时机dispatcherservlet 之前和之后

三、interceptor(拦截器)

3.1 原理

interceptor 是 spring mvc 提供的机制,运行在 dispatcherservlet 内部,可以感知到 handlerexecutionchain(即哪个 controller 方法将要执行)。

dispatcherservlet
    ├── prehandle()  →  controller 执行前
    ├── posthandle() →  controller 返回后,视图渲染前
    └── aftercompletion() → 视图渲染完成后(即使有异常也会执行)

3.2 用法

import jakarta.servlet.http.httpservletrequest;
import jakarta.servlet.http.httpservletresponse;
import org.springframework.stereotype.component;
import org.springframework.web.servlet.handlerinterceptor;

/**
 * 登录校验拦截器
 */
@component
public class logininterceptor implements handlerinterceptor {

    @override
    public boolean prehandle(httpservletrequest request, httpservletresponse response,
                             object handler) throws exception {
        string token = request.getheader("authorization");
        if (token == null || token.isempty()) {
            response.setstatus(401);
            response.getwriter().write("未登录");
            return false; // 中断请求
        }
        system.out.println("[interceptor] prehandle: token=" + token);
        return true; // 放行
    }

    @override
    public void posthandle(httpservletrequest request, httpservletresponse response,
                           object handler, modelandview modelandview) throws exception {
        system.out.println("[interceptor] posthandle: controller 执行完毕");
    }

    @override
    public void aftercompletion(httpservletrequest request, httpservletresponse response,
                                object handler, exception ex) throws exception {
        system.out.println("[interceptor] aftercompletion: 请求结束, ex=" + ex);
    }
}

注册拦截器并配置拦截路径:

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 webmvcconfig implements webmvcconfigurer {

    @override
    public void addinterceptors(interceptorregistry registry) {
        registry.addinterceptor(new logininterceptor())
                .addpathpatterns("/api/**")       // 拦截路径
                .excludepathpatterns("/api/login"); // 排除路径
    }
}

3.3 特点

特点说明
拦截范围controller 请求(不拦截静态资源)
能否获取 controller 信息可以(handler 参数包含 handlermethod
能否中断请求可以(prehandle 返回 false
prehandlecontroller 执行前,返回 false 中断
posthandlecontroller 正常返回后执行(抛异常则不执行)
aftercompletion最终执行(无论是否异常)

注意posthandle 在 controller 抛出异常时不会执行,但 aftercompletion 一定会执行

四、aop(面向切面编程)

4.1 原理

aop 是 spring 容器级别的机制,基于动态代理(jdk 或 cglib),可以拦截 spring bean 的方法调用。它不局限于 controller,可以作用于任何 bean。

调用 target.method()
    ↓
代理对象
    ├── @before         →  方法执行前
    ├── @afterreturning  →  方法正常返回后
    ├── @afterthrowing   →  方法抛出异常后
    ├── @after           →  方法结束后(无论成功失败)
    └── @around          →  环绕(最强大,可控制是否执行)

4.2 用法

import lombok.extern.slf4j.slf4j;
import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.component;

/**
 * 接口耗时统计切面
 */
@slf4j
@aspect
@component
public class timelogaspect {

    /**
     * 定义切入点:controller 包下所有 public 方法
     */
    @pointcut("execution(public * com.example.demo.controller.*.*(..))")
    public void controllerpointcut() {
    }

    /**
     * 环绕通知:统计方法执行耗时
     */
    @around("controllerpointcut()")
    public object around(proceedingjoinpoint pjp) throws throwable {
        long start = system.currenttimemillis();
        string methodname = pjp.getsignature().toshortstring();

        log.info("[aop] 方法开始: {}", methodname);

        try {
            object result = pjp.proceed(); // 执行目标方法
            long cost = system.currenttimemillis() - start;
            log.info("[aop] 方法结束: {}, 耗时 {}ms", methodname, cost);
            return result;
        } catch (throwable e) {
            long cost = system.currenttimemillis() - start;
            log.error("[aop] 方法异常: {}, 耗时 {}ms", methodname, cost, e);
            throw e;
        }
    }

    /**
     * 前置通知
     */
    @before("controllerpointcut()")
    public void before() {
        // 在 @around 的 proceed() 之前执行
    }
}

4.3 特点

特点说明
拦截范围任何 spring bean 的方法(不限于 controller)
能否获取方法参数可以(joinpoint.getargs()
能否修改参数可以(@around 中修改 args 后 proceed)
能否修改返回值可以(@around 中替换返回值)
能否中断执行可以(@around 中不调用 proceed)

五、listener(监听器)

5.1 原理

监听器是观察者模式的实现,用于监听容器或应用中发生的事件。spring boot 中有两种监听器:

类型接口事件
servlet 监听器servletrequestlistener请求创建/销毁
spring 事件监听器applicationlistener应用启动、刷新、自定义事件

5.2 servlet 请求监听器

import jakarta.servlet.servletrequestevent;
import jakarta.servlet.servletrequestlistener;
import jakarta.servlet.annotation.weblistener;
import org.springframework.stereotype.component;

/**
 * servlet 请求监听器
 */
@component
public class requestlistener implements servletrequestlistener {

    @override
    public void requestinitialized(servletrequestevent sre) {
        system.out.println("[listener] 请求创建: " + sre.getservletrequest());
    }

    @override
    public void requestdestroyed(servletrequestevent sre) {
        system.out.println("[listener] 请求销毁");
    }
}

5.3 spring 事件监听器

import org.springframework.context.event.eventlistener;
import org.springframework.stereotype.component;

/**
 * spring 事件监听器
 */
@component
public class springeventlistener {

    /**
     * 监听应用启动完成事件
     */
    @eventlistener
    public void onapplicationready(applicationreadyevent event) {
        system.out.println("[listener] 应用启动完成");
    }

    /**
     * 监听自定义事件
     */
    @eventlistener
    public void onordercreated(ordercreatedevent event) {
        system.out.println("[listener] 收到订单创建事件: " + event.getorderid());
    }
}

自定义事件:

import lombok.getter;
import org.springframework.context.applicationevent;

/**
 * 订单创建事件
 */
@getter
public class ordercreatedevent extends applicationevent {

    private final string orderid;

    public ordercreatedevent(object source, string orderid) {
        super(source);
        this.orderid = orderid;
    }
}

发布事件:

import org.springframework.context.applicationeventpublisher;
import org.springframework.stereotype.service;

@service
public class orderservice {

    private final applicationeventpublisher eventpublisher;

    public orderservice(applicationeventpublisher eventpublisher) {
        this.eventpublisher = eventpublisher;
    }

    public void createorder(string orderid) {
        // 业务逻辑...
        system.out.println("订单创建: " + orderid);

        // 发布事件
        eventpublisher.publishevent(new ordercreatedevent(this, orderid));
    }
}

与 filter/interceptor 的区别:listener 是被动的事件回调,不能拦截或中断请求流程。

六、controlleradvice(全局异常与数据绑定)

6.1 原理

@restcontrolleradvice / @controlleradvice 是 spring mvc 提供的全局增强机制,可以处理 controller 层的异常、全局数据绑定、全局数据预处理。

6.2 全局异常处理

import lombok.extern.slf4j.slf4j;
import org.springframework.http.httpstatus;
import org.springframework.web.bind.annotation.*;

import java.util.hashmap;
import java.util.map;

/**
 * 全局异常处理器
 */
@slf4j
@restcontrolleradvice
public class globalexceptionhandler {

    /**
     * 处理业务异常
     */
    @exceptionhandler(businessexception.class)
    @responsestatus(httpstatus.ok)
    public map<string, object> handlebusiness(businessexception e) {
        log.warn("业务异常: {}", e.getmessage());
        map<string, object> result = new hashmap<>();
        result.put("code", e.getcode());
        result.put("message", e.getmessage());
        return result;
    }

    /**
     * 处理参数校验异常
     */
    @exceptionhandler(illegalargumentexception.class)
    @responsestatus(httpstatus.bad_request)
    public map<string, object> handleillegalarg(illegalargumentexception e) {
        log.warn("参数异常: {}", e.getmessage());
        map<string, object> result = new hashmap<>();
        result.put("code", "400");
        result.put("message", e.getmessage());
        return result;
    }

    /**
     * 兜底:处理所有未捕获异常
     */
    @exceptionhandler(exception.class)
    @responsestatus(httpstatus.internal_server_error)
    public map<string, object> handleexception(exception e) {
        log.error("系统异常", e);
        map<string, object> result = new hashmap<>();
        result.put("code", "500");
        result.put("message", "系统繁忙");
        return result;
    }
}

6.3 全局数据绑定

@restcontrolleradvice
public class globaldatabinder {

    @initbinder
    public void initbinder(webdatabinder binder) {
        // 注册自定义编辑器
        binder.registercustomeditor(string.class, new stringtrimmereditor(true));
    }
}

6.4 全局数据预处理

@restcontrolleradvice
public class globalrequestbodyadvice {

    @modelattribute
    public void addcommonattributes(model model) {
        model.addattribute("servertime", system.currenttimemillis());
    }
}

关键@exceptionhandler 只能捕获 controller 层抛出的异常,不能捕获 filter 层的异常。

七、handlermethodargumentresolver(参数处理器)

7.1 原理

参数处理器负责将 http 请求中的数据解析为 controller 方法的入参。spring mvc 内置了多个处理器:

内置处理器处理的注解
requestparammethodargumentresolver@requestparam
pathvariablemethodargumentresolver@pathvariable
requestbodymethodargumentresolver@requestbody
requestheadermethodargumentresolver@requestheader
modelattributemethodprocessor@modelattribute

当内置处理器不满足需求时,可以自定义。

7.2 自定义参数处理器示例

场景:从 token 中解析当前登录用户,直接注入 controller 方法。

import org.springframework.core.methodparameter;
import org.springframework.stereotype.component;
import org.springframework.web.bind.support.webdatabinderfactory;
import org.springframework.web.context.request.nativewebrequest;
import org.springframework.web.method.support.handlermethodargumentresolver;
import org.springframework.web.method.support.modelandviewcontainer;

import jakarta.servlet.http.httpservletrequest;

/**
 * 自定义参数处理器:解析 @currentuser 注解
 */
@component
public class currentuserargumentresolver implements handlermethodargumentresolver {

    @override
    public boolean supportsparameter(methodparameter parameter) {
        return parameter.hasparameterannotation(currentuser.class)
                && parameter.getparametertype().equals(userinfo.class);
    }

    @override
    public object resolveargument(methodparameter parameter,
                                  modelandviewcontainer mavcontainer,
                                  nativewebrequest webrequest,
                                  webdatabinderfactory binderfactory) throws exception {
        httpservletrequest request = webrequest.getnativerequest(httpservletrequest.class);
        string token = request.getheader("authorization");

        // 从 token 解析用户信息(实际项目中通常从 jwt 或缓存中获取)
        userinfo user = parsetoken(token);
        return user;
    }

    private userinfo parsetoken(string token) {
        userinfo user = new userinfo();
        user.setid(1001l);
        user.setname("张三");
        return user;
    }
}

自定义注解:

import java.lang.annotation.*;

@target(elementtype.parameter)
@retention(retentionpolicy.runtime)
@documented
public @interface currentuser {
}

用户信息类:

import lombok.data;

@data
public class userinfo {
    private long id;
    private string name;
}

注册参数处理器:

import org.springframework.context.annotation.configuration;
import org.springframework.web.method.support.handlermethodargumentresolver;
import org.springframework.web.servlet.config.annotation.webmvcconfigurer;

import java.util.list;

@configuration
public class webmvcconfig implements webmvcconfigurer {

    private final currentuserargumentresolver currentuserresolver;

    public webmvcconfig(currentuserargumentresolver currentuserresolver) {
        this.currentuserresolver = currentuserresolver;
    }

    @override
    public void addargumentresolvers(list<handlermethodargumentresolver> resolvers) {
        resolvers.add(currentuserresolver);
    }
}

在 controller 中使用:

@restcontroller
@requestmapping("/api/user")
public class usercontroller {

    @getmapping("/profile")
    public map<string, object> getprofile(@currentuser userinfo user) {
        map<string, object> result = new hashmap<>();
        result.put("id", user.getid());
        result.put("name", user.getname());
        return result;
    }
}

八、handlermethodreturnvaluehandler(返回值处理器)

8.1 原理

返回值处理器负责将 controller 方法的返回值转换为 http 响应。内置处理器包括:

内置处理器处理场景
requestresponsebodymethodprocessor@responsebody / @restcontroller
modelandviewmethodreturnvaluehandler返回 modelandview
viewmethodreturnvaluehandler返回 string(视图名)
httpentitymethodprocessor返回 responseentity

8.2 自定义返回值处理器示例

场景:controller 方法返回实体对象,自动包装为统一响应格式 result<t>

import org.springframework.core.methodparameter;
import org.springframework.http.mediatype;
import org.springframework.http.converter.httpmessageconverter;
import org.springframework.http.server.serverhttprequest;
import org.springframework.http.server.serverhttpresponse;
import org.springframework.web.bind.annotation.restcontrolleradvice;
import org.springframework.web.servlet.mvc.method.annotation.responsebodyadvice;

import java.util.hashmap;
import java.util.map;

/**
 * 统一返回值包装
 * <p>
 * 通过 responsebodyadvice 实现,它本质上是返回值处理器的增强钩子。
 */
@restcontrolleradvice
public class globalresponsehandler implements responsebodyadvice<object> {

    @override
    public boolean supports(methodparameter returntype,
                            class<? extends httpmessageconverter<?>> convertertype) {
        // 如果已经是 result 类型,则不再包装
        return !returntype.getparametertype().equals(result.class);
    }

    @override
    public object beforebodywrite(object body,
                                  methodparameter returntype,
                                  mediatype selectedcontenttype,
                                  class<? extends httpmessageconverter<?>> selectedconvertertype,
                                  serverhttprequest request,
                                  serverhttpresponse response) {
        map<string, object> result = new hashmap<>();
        result.put("code", 0);
        result.put("message", "success");
        result.put("data", body);
        return result;
    }
}

统一响应类:

import lombok.data;

@data
public class result<t> {
    private int code;
    private string message;
    private t data;

    public static <t> result<t> success(t data) {
        result<t> r = new result<>();
        r.setcode(0);
        r.setmessage("success");
        r.setdata(data);
        return r;
    }

    public static <t> result<t> fail(string message) {
        result<t> r = new result<>();
        r.setcode(500);
        r.setmessage(message);
        return r;
    }
}

注意responsebodyadvice 不是完整的 returnvaluehandler,而是在 requestresponsebodymethodprocessor 内部的增强钩子。完整自定义需要实现 handlermethodreturnvaluehandler 接口并注册,但实际项目中 responsebodyadvice 已足够。

九、横向对比

9.1 执行顺序

http 请求到达
    │
    ├── 1. listener.requestinitialized()    ← servlet 请求监听器
    │
    ├── 2. filter.dofilter() [请求阶段]     ← 过滤器
    │       (filter1 → filter2 → ...)
    │
    ├── 3. dispatcherservlet
    │       │
    │       ├── 3.1 interceptor.prehandle()  ← 拦截器-前置
    │       │
    │       ├── 3.2 argumentresolver         ← 参数处理器
    │       │
    │       ├── 3.3 aop @around [前半段]     ← aop(如果有)
    │       │       ├── aop @before
    │       │       ├── controller 方法执行
    │       │       └── aop @afterreturning / @afterthrowing
    │       │       └── aop @after
    │       │       └── aop @around [后半段]
    │       │
    │       ├── 3.4 returnvaluehandler       ← 返回值处理器
    │       │       └── responsebodyadvice
    │       │
    │       ├── 3.5 interceptor.posthandle() ← 拦截器-后置
    │       │
    │       └── 3.6 interceptor.aftercompletion() ← 拦截器-完成
    │
    ├── 4. filter.dofilter() [响应阶段]
    │       (... → filter2 → filter1)
    │
    └── 5. listener.requestdestroyed()       ← servlet 请求监听器

异常分支:
    controller 抛出异常
        → aop @afterthrowing
        → interceptor.aftercompletion()
        → @restcontrolleradvice @exceptionhandler
    filter 抛出异常
        → 不会进入 controlleradvice(需在 filter 中自行处理)

核心记忆:filter → interceptor.prehandle → argumentresolver → aop → controller → returnvaluehandler → interceptor.posthandle → interceptor.aftercompletion → filter

9.2 功能对比矩阵

能力filterinterceptoraoplistenercontrolleradviceargumentresolverreturnvaluehandler
拦截所有请求❌ 仅 controller❌ 仅 bean 方法
拦截静态资源
获取 controller 方法信息
获取方法参数值✅(可修改)
修改方法参数
修改返回值
中断请求
处理异常✅(自行处理)
感知事务
作用范围servlet 容器spring mvcspring 容器servlet/springspring mvcspring mvcspring mvc

9.3 适用场景对比

场景推荐组件理由
请求日志记录filter能记录所有请求(含静态资源),且在最早阶段拦截
登录鉴权interceptor只需拦截 controller 请求,可获取 handler 信息,可排除特定路径
权限校验interceptor同上,且可获取 controller 注解
接口耗时统计aop可精确到方法级别,可统计 service 层耗时
参数校验/签名aop 或 interceptoraop 更灵活(可作用于 service 层),interceptor 更简单
统一返回值包装responsebodyadvice不侵入 controller 代码,自动包装所有返回值
自定义参数注入argumentresolver@currentuser 注入登录用户
全局异常处理controlleradvice统一处理 controller 异常,避免 try-catch 散落各处
跨域处理filter 或 corsfilter在最早阶段处理 cors 预检请求
请求体加密/解密filter + wrapper需要在请求到达 controller 前修改请求体
事件通知listener异步解耦,如订单创建后发通知
接口限流filter 或 interceptorfilter 更早拦截减少资源消耗

9.4 功能交叉点分析

filter vs interceptor — 都能拦截请求

相同点:

  • 都能在请求前后执行逻辑
  • 都能中断请求
  • 都能获取 httpservletrequest / httpservletresponse

不同点:

  • filter 拦截所有请求(含静态资源),interceptor 只拦截 controller
  • filter 不感知 controller 信息,interceptor 可以获取 handlermethod
  • filter 在 dispatcherservlet 外,interceptor 在内

interceptor 的 excludepathpatterns 配置更灵活

选型建议:

  • 需要拦截所有请求 → filter(如跨域、字符编码)
  • 只需拦截 controller → interceptor(如登录校验、权限控制)

interceptor vs aop — 都能拦截 controller 方法

相同点:

  • 都能在 controller 方法前后执行逻辑
  • 都能获取方法签名和参数
  • 都能中断执行

不同点:

  • interceptor 只能拦截 controller,aop 能拦截任何 bean
  • interceptor 有 posthandle(视图渲染前),aop 没有
  • aop 更灵活(@around 可控制是否执行、可修改参数和返回值)
  • interceptor 更简单(实现接口即可,无需切点表达式)
  • aop 基于动态代理,同类内部方法调用不走代理(自调用问题)

选型建议:

  • 只需拦截 controller、逻辑简单 → interceptor
  • 需要拦截 service 层、需要修改参数或返回值 → aop

controlleradvice vs interceptor — 都能处理异常

相同点:都在 spring mvc 层面工作

不同点:

  • controlleradvice 专门处理异常,interceptor 的 aftercompletion 只能感知异常但不能处理
  • controlleradvice 可以针对不同异常类型返回不同响应
  • interceptor 无法修改异常的走向,异常会继续传播

选型建议:异常处理 → 始终用 controlleradvice

filter vs interceptor — 都能做日志记录

filter 做日志:

  • 能记录所有请求(含 404、静态资源)
  • 能获取最终响应状态码
  • 不能获取 controller 类名和方法名

interceptor 做日志:

  • 能获取 controller 类名和方法名
  • 可以排除不需要记录的路径
  • 不能记录非 controller 请求(如 404)

选型建议:

  • 访问日志(access log)→ filter
  • 接口调用日志(需要方法名)→ interceptor 或 aop

十、实战:组合使用示例

一个典型的 spring boot 项目通常同时使用多种组件:

import org.springframework.context.annotation.configuration;
import org.springframework.web.method.support.handlermethodargumentresolver;
import org.springframework.web.servlet.config.annotation.interceptorregistry;
import org.springframework.web.servlet.config.annotation.webmvcconfigurer;

import java.util.list;

/**
 * web mvc 统一配置
 */
@configuration
public class webmvcconfig implements webmvcconfigurer {

    private final logininterceptor logininterceptor;
    private final currentuserargumentresolver currentuserresolver;

    public webmvcconfig(logininterceptor logininterceptor,
                        currentuserargumentresolver currentuserresolver) {
        this.logininterceptor = logininterceptor;
        this.currentuserresolver = currentuserresolver;
    }

    @override
    public void addinterceptors(interceptorregistry registry) {
        registry.addinterceptor(logininterceptor)
                .addpathpatterns("/api/**")
                .excludepathpatterns("/api/login", "/api/register");
    }

    @override
    public void addargumentresolvers(list<handlermethodargumentresolver> resolvers) {
        resolvers.add(currentuserresolver);
    }
}

各组件分工:

组件职责
filter请求日志、跨域处理、字符编码
interceptor登录校验、权限控制
aop接口耗时统计、操作日志
controlleradvice全局异常处理
argumentresolver@currentuser 注入登录用户
responsebodyadvice统一返回值包装
listener应用启动初始化、订单事件通知

controller 代码保持极简:

@restcontroller
@requestmapping("/api/order")
public class ordercontroller {

    private final orderservice orderservice;

    public ordercontroller(orderservice orderservice) {
        this.orderservice = orderservice;
    }

    @postmapping("/create")
    public ordervo createorder(@currentuser userinfo user,
                               @requestbody @valid ordercreaterequest request) {
        return orderservice.createorder(user.getid(), request);
    }
}

执行流程:

  • filter        → 记录请求日志
  • interceptor   → 校验登录 token
  • argumentresolver → 解析 token,注入 userinfo
  • aop @around   → 开始计时
  • controller    → 执行业务逻辑
  • aop @around   → 结束计时,记录日志
  • responsebodyadvice → 包装返回值为 {code, message, data}
  • interceptor.aftercompletion → 清理资源
  • filter        → 记录响应日志

十一、常见误区与最佳实践

11.1 常见误区

误区正解
filter 中抛异常会被 controlleradvice 捕获❌ 不会。filter 在 dispatcherservlet 之外,需要自行 try-catch
interceptor 的 posthandle 在异常时也会执行❌ controller 抛异常时 posthandle 不执行,只有 aftercompletion 执行
aop 可以拦截同类内部方法调用this.method() 不走代理,只有外部调用才走代理
listener 可以中断请求❌ listener 是事件回调,不能中断流程
responsebodyadvice 对所有返回值生效❌ 只对 @responsebody / @restcontroller 的方法生效
多个 interceptor 的 posthandle 按注册顺序执行❌ posthandle 和 aftercompletion 按注册的逆序执行

11.2 多个拦截器的执行顺序

拦截器注册顺序:a → b → c

prehandle 执行顺序:a → b → c(正序)
posthandle 执行顺序:c → b → a(逆序)
aftercompletion 执行顺序:c → b → a(逆序)

如果 b 的 prehandle 返回 false:
  a.prehandle ✅
  b.prehandle ❌(返回 false)
  c.prehandle 不执行
  controller 不执行
  posthandle 都不执行
  aftercompletion:a.aftercompletion ✅(已 prehandle 成功的会执行)
  c.aftercompletion 不执行

11.3 最佳实践

  1. 职责单一:每个组件只做一件事,不要在 filter 中做业务逻辑
  2. 异常处理分层:filter 异常自行处理,controller 异常交给 controlleradvice
  3. 避免循环依赖:filter 中注入 bean 时注意 bean 的初始化时机
  4. 拦截器路径配置:用 excludepathpatterns 排除登录、注册等公开接口
  5. aop 自调用问题:同类方法内部调用不走代理,需要通过 aopcontext.currentproxy() 或拆分到不同类
  6. 参数处理器优先级:自定义 argumentresolver 添加到列表末尾,避免覆盖内置处理器
  7. responsebodyadvice 判断类型:在 supports() 中排除已是 result 类型的返回值,避免重复包装

十二、总结

12.1 选型决策树

需要在请求最外层拦截?
  ├── 是 → filter
  │        (跨域、编码、访问日志)
  └── 否 → 需要拦截 controller 方法?
            ├── 是 → 需要修改参数或返回值?
            │        ├── 是 → aop
            │        │        (耗时统计、参数处理)
            │        └── 否 → 需要获取 handler 信息?
            │                 ├── 是 → interceptor
            │                 │        (登录校验、权限控制)
            │                 └── 否 → aop 或 interceptor 均可
            └── 否 → 需要处理异常?
                      ├── 是 → controlleradvice
                      │        (全局异常处理)
                      └── 否 → 需要自定义参数注入?
                                ├── 是 → argumentresolver
                                │        (@currentuser)
                                └── 否 → 需要统一包装返回值?
                                          ├── 是 → responsebodyadvice
                                          └── 否 → 需要监听事件?
                                                    └── listener

12.2 核心要点速查

  1. filter 在 dispatcherservlet 外,拦截所有请求,适合跨域、编码、访问日志
  2. interceptor 在 dispatcherservlet 内,只拦截 controller,适合登录鉴权、权限控制
  3. aop 基于 spring 动态代理,能拦截任何 bean 方法,适合耗时统计、操作日志
  4. listener 是事件回调,不能中断请求,适合应用初始化、事件通知
  5. controlleradvice 专门处理 controller 层异常,不能捕获 filter 层异常
  6. argumentresolver 自定义参数解析,如 @currentuser 注入登录用户
  7. responsebodyadvice 统一包装返回值,不侵入 controller 代码
  8. 执行顺序:filter → interceptor.prehandle → argumentresolver → aop → controller → returnvaluehandler → interceptor.posthandle → aftercompletion → filter
  9. interceptor 的 posthandle 和 aftercompletion 按注册逆序执行
  10. aop 自调用不走代理,需通过 aopcontext.currentproxy() 解决

以上就是springboot中请求处理组件全面对比与选型指南的详细内容,更多关于springboot请求处理组件的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com