Work

spring-boot-middleware

Spring Boot
Middleware
Filter
Interceptor
ControllerAdvice
AOP
Chain of Responsibility
JWT
Image 3

TY Multiverse Spring Boot 中間件與責任鏈模式實戰指南

🧠 核心概念:Filter / Middleware 是什麼?

無論是 Servlet FilterSpring Security FilterSpring Cloud Gateway Filter、或是 WebFlux 的 WebFilter,它們在本質上都是**「責任鏈模式(Chain of Responsibility Pattern)」**的具體實現。

定義: 一連串具相同介面的「處理節點」,每個節點可選擇 → 攔截請求(中止鏈式處理) → 或 放行(交給下一個節點處理) 最後到達實際的業務處理(Controller 或 Handler)。

🔍 簡單比喻

🏦 銀行辦業務

  • 保安(Filter)檢查身份證件
  • 服務台(Interceptor)登記需求並記錄時間
  • 業務員(Controller)處理具體業務
  • 緊急處理中心(@ControllerAdvice)處理各種意外

🚀 為什麼能做這些事情?

HTTP 請求生命週期:HTTP請求 → Tomcat → Filter鏈 → DispatcherServlet → Interceptor鏈 → Controller → 業務邏輯

⚙️ 功能實現原理

功能為什麼能做到實作方式
JWT 認證攔截 Header,解析 tokenSecurity Filter
限流檢查請求頻率RateLimiter Filter
CORS改寫 Response HeaderCORS Filter
日誌記錄讀取 Request/ResponseLogging Filter/Interceptor
異常處理包裹整個請求流程@ControllerAdvice

🔄 Spring Boot Request 生命週期全解析

Spring Boot 處理一個 HTTP 請求的完整生命週期可分為 8 個階段,每個階段都可以被不同類型的 Middleware(Filter、Interceptor、AOP、ControllerAdvice)攔截或擴展。

🧩 整體流程圖

Client

[1] Servlet Container (Tomcat/Jetty)

[2] Filter Chain (如 JWTFilter, CorsFilter)

[3] DispatcherServlet

[4] HandlerMapping (尋找對應的 Controller)

[5] HandlerInterceptor (preHandle)

[6] Controller (執行業務邏輯)

[7] HandlerInterceptor (postHandle / afterCompletion)

[8] ViewResolver / ResponseBody 返回

@ControllerAdvice / ExceptionHandler(全域異常處理)

Response 回傳 Client

🧮 演算法與資料結構深度剖析

總體觀:整個 Request Flow = 一條「有向鏈結串列 (Directed Linked List) + 責任鏈 (Chain of Responsibility)」

Client → [1] → [2] → [3] → [4] → [5pre] → [6] → [7post] → [8] → ExceptionHandler → Response

這個鏈條可以抽象成:

interface Handler {
    Response handle(Request req, Chain next);
}

每一層都:

  • 接收請求
  • 決定是否往下一層傳遞 (next.handle())
  • 處理回應
  • 可包裹上下層(形成遞迴結構)

這正是**責任鏈模式 (Chain of Responsibility Pattern)**的演算法表現。

🧱 一層層用演算法與資料結構角度剖析

🧱 [1] Servlet Container

資料結構觀點:執行緒池 + 阻塞佇列(ThreadPool + BlockingQueue)
演算法類型:Producer-Consumer(生產者消費者模式)

HTTP Socket Request → 放入請求佇列 → 工作執行緒取出處理

Tomcat 透過 Acceptor Thread 接收請求,放入 Request Queue;Worker Threads 從 Queue 取任務處理,並呼叫 Filter Chain。屬於典型的 I/O 多工 + 任務分派演算法。

➡️ 功能類似於 Dispatcher Pattern:I/O 與任務解耦。

🔗 [2] Filter Chain

資料結構觀點:單向鏈結串列 (Linked List)
演算法類型:責任鏈 (Chain of Responsibility)

class FilterChain {
    private List<Filter> filters;
    private int index = 0;

    public void doFilter(Request req, Response res) {
        if (index < filters.size()) {
            filters.get(index++).doFilter(req, res, this);
        }
    }
}

每個 Filter 都包裹下一個 Filter,可提前中止(如認證失敗),支援動態插入與排序(LinkedList 結構最合適)。

➡️ 類似於遞歸呼叫的「包裝式函數」;可視為「遞歸鏈表的疊層結構」。

🚦 [3] DispatcherServlet

資料結構觀點:Router Map(HashMap<String, Handler>)
演算法類型:查表 (Hash lookup) + 控制流程調度器 (Dispatcher Pattern)

handler = handlerMappings.get(url);
handlerAdapter.handle(handler, request);

DispatcherServlet 根據 URL/Method 等條件查表,映射到對應 Controller 的 HandlerMethod,對應到演算法的「分派器」或「策略選擇器」。

➡️ 核心演算法:O(1) 查找 + 流程控制

🗺️ [4] HandlerMapping

資料結構觀點:多層索引樹(HashMap + Trie 結構)
演算法類型:模式匹配 (Pattern Matching)

GET /api/user/{id}  →  Controller: UserController#getUserById()

URL pattern 可帶參數、萬用字元,Spring MVC 使用 AntPathMatcher / PathPatternParser,實際上是 Trie + 字串匹配演算法。

➡️ 類似於路由表匹配演算法,可視為 Trie 路徑搜尋

🧩 [5] HandlerInterceptor (preHandle)

資料結構觀點:棧 (Stack)
演算法類型:遞歸回溯(Pre/Post Handler 形成雙向呼叫)

for (Interceptor i : interceptors) {
    if (!i.preHandle(req)) break;
}

多個攔截器按順序前進 (preHandle),回傳時反向執行 (afterCompletion),資料結構行為與呼叫棧相同(LIFO)。

➡️ 執行邏輯為遞歸:前進 → 執行 → 回溯

🎯 [6] Controller

資料結構觀點:函式呼叫棧 (Call Stack)
演算法類型:命令模式 (Command Pattern)

Response handle(Request req) {
    return userService.findUser(req.id);
}

每個 Controller 方法封裝成一個 Command,DispatcherServlet 執行該 Command,可透過 AOP 插入額外邏輯(如 Transaction Proxy)。

➡️ 資料結構層面:函式棧 + 動態代理(Proxy Chain)

🧱 [7] HandlerInterceptor (postHandle / afterCompletion)

資料結構觀點:棧 (Stack)(呼叫回溯階段)
演算法類型:遞歸回溯 (Recursive Backtracking)

for (Interceptor i : reverse(interceptors)) {
    i.afterCompletion(req, res);
}

回溯過程逐層釋放,可在此計時、記錄 log、釋放資源。

➡️ 呼叫鏈結的反向遍歷階段

🧾 [8] ViewResolver / ResponseBody

資料結構觀點:策略表 (Strategy Pattern) + 序列化樹 (Object Graph)
演算法類型:策略選擇 + 遞歸序列化

使用 HttpMessageConverter 決定輸出格式(JSON / XML / HTML),ObjectMapper 對象序列化時,遍歷物件圖(樹狀資料結構)。

response = jsonMapper.writeValueAsString(object);

➡️ 是典型的策略 + 遞歸樹遍歷演算法

⚠️ ExceptionHandler / @ControllerAdvice

資料結構觀點:全域異常表 (HashMap<Class<?>, Handler>)
演算法類型:動態分派 (Dynamic Dispatch)

根據 Exception 類型查找對應處理器,若未匹配 → 尋找父類型(繼承鏈搜索)。

➡️ 本質上是「型別查表演算法」。

🧮 小結:演算法對應總表

階段核心資料結構對應演算法核心概念
[1] Servlet ContainerThreadPool + QueueProducer-Consumer任務分派
[2] Filter ChainLinkedListChain of Responsibility外層包裝
[3] DispatcherServletHashMapDispatcher / Lookup中央分發
[4] HandlerMappingTrie / HashMapPattern MatchingURL 路由
[5] Interceptor (pre)StackRecursive Forward前置邏輯
[6] ControllerCall StackCommand Pattern執行核心邏輯
[7] Interceptor (post)StackBacktracking回溯釋放
[8] ViewResolverStrategy + Object Tree遞歸序列化結果輸出
ExceptionHandlerHashMap<Class<?>>Dynamic Dispatch錯誤回復

🧩 最後一句總結

Spring Boot 的 Request Flow,其實就是一條「動態鏈式責任鏈」,以鏈表、棧、Map、策略表、任務佇列為核心資料結構,結合 Dispatcher / 責任鏈 / 策略 / 遞歸 等演算法設計,實現高可擴充、可插拔、低耦合的 Request 處理框架。

🔍 跨語言架構對比:Middleware Pipeline 通用設計

🧠 核心觀念:Middleware Pipeline = Filter Chain = 責任鏈

無論是 Servlet FilterSpring Security FilterSpring Cloud Gateway Filter、或是 WebFlux 的 WebFilter,它們在本質上都是**「責任鏈模式(Chain of Responsibility Pattern)」**的具體實現。

所有 Web Framework 的請求流程基本上都是:

Request → 一連串中介層 / 過濾器 → Handler / Controller → Response

換句話說,它們只是「在不同語言中用不同名字」實作出同一種資料結構: ➡️ 鏈式呼叫(Linked Chain)+遞歸傳遞(next())+前後邏輯包裹(Around pattern)

🧩 對應到不同語言體系的結構比較表

系統 / 語言對應結構與 Spring MVC 的對照
Java (Spring MVC)FilterChain + HandlerInterceptorFilter + Interceptor 對應中介層
Python (Django)Middleware(在 settings.MIDDLEWARE 中設定)與 Filter/Interceptor 類似,支援 process_request / process_response
Python (FastAPI / Starlette)Middleware(decorator 型或 class 型)支援 async middleware、AOP 風格包裹請求
Node.js (Express / Koa)app.use(fn(req, res, next))next() 呼叫下一層,鏈式結構完全一致
Go (Gin / Fiber)Use(middleware) + Context.Next()Go 版本的責任鏈模式
ASP.NET Core (C#)RequestDelegate + UseMiddleware()也是 pipeline 模式
Ruby on RailsRack middleware也是「request-response」環狀鏈設計

🔥 FastAPI 深度對比:8 層流水線結構

🧭 FastAPI vs Spring Boot 對照總覽表

Spring Boot 階段FastAPI / Starlette 對應層級功能對應說明
[1] Servlet Container (Tomcat/Jetty)ASGI Server (Uvicorn / Hypercorn)負責接收 HTTP 請求與建立 Request/Response 物件。相當於 Servlet Container。
[2] Filter Chain (FilterChain.doFilter)Middleware Stack (app.add_middleware)一連串中介層,如 Logging、CORS、RateLimit、Auth 等。執行順序 = 責任鏈。
[3] DispatcherServletRouter (Starlette Routing 層)將請求分派給正確的 Endpoint(route handler)。相當於請求分發中心。
[4] HandlerMapping路由比對 (Path + Method matching)根據 path / method 找出對應的 @app.get(“/users”) 函數。
[5] HandlerInterceptor (preHandle)Dependency Injection / Request Lifecycle Hooks (e.g. Depends)在進入 endpoint 前進行驗證、session 檢查等。
[6] Controller (Controller / Service)FastAPI Endpoint Function (async def handler)執行實際的業務邏輯。
[7] HandlerInterceptor (postHandle / afterCompletion)Middleware 的 response return 階段Middleware 可在 Response 回傳後進行修改或記錄。
[8] ViewResolver / ResponseBodyResponseModel / JSONResponse / TemplateResponseFastAPI 負責將 Python 對象轉成 JSON / HTML 回應。
@ControllerAdvice / ExceptionHandlerExceptionMiddleware / @app.exception_handler統一異常攔截、回應格式化。

🧩 FastAPI 的「8 層流水線」可視化流程

Client

[1] ASGI Server (Uvicorn)

[2] Middleware Stack
      ├─ CORS
      ├─ Logging
      ├─ Authentication
      └─ Custom Middleware (Rate Limit / Trace)

[3] Router 分派

[4] 路由比對 (path=/user, method=GET)

[5] Dependency Resolution (preHandle)

[6] Endpoint Function 執行

[7] Response 回傳(Middleware 可 post 處理)

[8] ResponseModel / JSONResponse 序列化

ExceptionMiddleware 捕捉錯誤 → 回傳標準格式

Response 傳回 Client

⚙️ FastAPI Middleware 實際範例(對應 Filter Chain)

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

# [2] Filter/Middleware
@app.middleware("http")
async def log_requests(request: Request, call_next):
    print(f"Incoming: {request.method} {request.url}")
    response = await call_next(request)  # 呼叫下一層(相當於 FilterChain.doFilter)
    print(f"Completed: {response.status_code}")
    return response

# [3~6] Dispatcher + Handler
@app.get("/hello")
async def hello_user():
    return {"msg": "Hello, World!"}

# [ExceptionHandler]
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    return JSONResponse(content={"error": str(exc)}, status_code=500)

執行順序會是: → log_requests pre → hello_user()log_requests post

這與 Spring Boot 的 Filter + Interceptor 呼叫鏈完全一致。

🧠 底層設計結構(演算法觀點)

FastAPI 的整個 middleware pipeline 是一個異步責任鏈 (async chain)

async def middleware1(req, next):
    pre1()
    await next(req)
    post1()

async def middleware2(req, next):
    pre2()
    await next(req)
    post2()

# 呼叫順序:
# pre1 → pre2 → handler → post2 → post1

這等價於 Spring 的:

filter1 -> filter2 -> controller -> filter2 post -> filter1 post

➡️ 都是鏈表 + 遞歸回傳的結構。FastAPI 只是用 await call_next(request) 代替 Java 的 chain.doFilter(req, res)

✅ 總結:FastAPI vs Spring Boot 對照精華

概念Spring BootFastAPI
容器Servlet ContainerASGI Server
過濾器Filter ChainMiddleware
分派器DispatcherServletRouter
路由對應HandlerMappingRoute Matching
前置邏輯HandlerInterceptor.preHandleDependencies / Middleware pre
業務處理ControllerEndpoint Function
後置邏輯postHandle / afterCompletionMiddleware post / response hook
異常處理@ControllerAdvice@app.exception_handler
回應輸出ViewResolver / ResponseBodyResponseModel / JSONResponse

📘 為什麼這些框架都設計為這 8 層?

這種結構符合 Web 伺服器要處理的「演算法需求」:

  • O(N) 鏈式遍歷(依序處理每個 middleware)
  • 可前後包裹的遞歸結構(像是棧 Stack,可支援 pre/post)
  • 易於擴展與組合(責任鏈可插拔)
  • 符合 HTTP pipeline 特性(每個階段都能改動 request/response)

實際上,你可以把整個流程看成一個「包層」的結構:

Client

[M1: CORS]

[M2: Logging]

[M3: Auth]

[M4: Controller]

[return response 回傳時再經過這些 middleware 的 post 處理]

這個結構在演算法層面上,其實是:

鏈表 + 遞歸(或堆疊)呼叫的責任鏈設計模式

🧮 抽象成資料結構模型

假設有 N 個中介層:

M1 → M2 → M3 → Controller

每個中介層都有:

void handle(Request req, Response res, Next next)

則整體演算法等價於:

handle_i(req, res):
    preProcess()
    next(req, res)  # 呼叫下一層
    postProcess()

這在執行上是一個「遞歸展開 → 回溯收斂」的過程,像:

M1.pre → M2.pre → M3.pre → Controller → M3.post → M2.post → M1.post

➡️ 這正是 Filter / Middleware 可以同時「修改 Request」與「攔截/修改 Response」的原因。

📋 架構設計理念總結

概念通用名稱資料結構 / 設計模式
Request PipelineMiddleware / Filter Chain責任鏈 (Chain of Responsibility)
Request HandlerController / Endpoint呼叫終端業務邏輯
Response HandlerViewResolver / Response Middleware處理輸出或錯誤包裝
全域錯誤處理ExceptionHandler / ErrorMiddleware頂層攔截異常

⚙️ 各階段詳細說明

階段元件主要工作可插入邏輯
1Servlet Container啟動 Web 容器、建立 ServletContext無(屬於容器層)
2Filter Chain最外層攔截,通常用於安全、限流、日誌JWT、CORS、RateLimiter
3DispatcherServletSpring MVC 的中央路由器AOP 攔截
4HandlerMapping動態匹配 Controller / Handler自定義路由邏輯
5HandlerInterceptorController 執行前後的可插拔邏輯驗證、監控、審計
6Controller業務邏輯執行AOP 橫切關注點
7ViewResolver/ResponseBody結果轉換與回傳回應格式化
8ExceptionResolver/ControllerAdvice統一錯誤處理與例外回傳全域異常處理

🧭 為什麼設計為這 8 個階段?

這不是偶然的,而是經過長期架構演進形成的分層設計,核心目的是**「高內聚 + 低耦合 + 可擴展 + 可插拔」**。

架構原則與設計理念

  1. Single Responsibility (單一職責):每一層只負責一件事
  2. Open/Closed Principle (開放封閉):可新增 Filter/Interceptor,不需改舊邏輯
  3. Separation of Concerns (關注點分離):協議層、框架層、業務層各自獨立
  4. Extensibility (可擴展性):支援 AOP、自定義 Filter、ExceptionResolver
  5. Consistency (一致性):不論錯誤或成功回應都經同一路徑處理

各階段核心價值

  • Servlet Container:統一協議層與執行緒管理,隔離框架與底層伺服器
  • Filter Chain:屬於 Servlet 規範,可在框架外層攔截原始 HTTP Request
  • DispatcherServlet:MVC 分層架構的中樞,統一流量入口和調度
  • HandlerMapping:使路由可配置、可擴充(支援自定義 handler 來源)
  • HandlerInterceptor:能拿到 Controller 資訊,適合業務層攔截
  • Controller:透過 IoC + AOP 讓業務邏輯專注「做事」
  • ViewResolver:抽象回應格式,讓 Controller 專注「回傳資料」
  • ControllerAdvice:保證「錯誤也有格式」,使客戶端能一致解析錯誤

設計精髓:每層解耦後可替換、可插拔,讓你在不改業務邏輯的情況下,自由插入框架功能。

🏗️ 三種中間件實戰

1. @ControllerAdvice:統一錯誤處理

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(404).body(
            new ErrorResponse(ex.getMessage(), HttpStatus.NOT_FOUND.value())
        );
    }
}

適用場景:統一處理所有異常,確保一致的錯誤響應格式。

2. Servlet Filter:JWT 認證

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) {

        String token = request.getHeader("Authorization");
        if (token != null && jwtService.validateToken(token)) {
            Authentication auth = jwtService.getAuthentication(token);
            SecurityContextHolder.getContext().setAuthentication(auth);
        }

        filterChain.doFilter(request, response);
    }
}

適用場景:需要在 Spring MVC 之前攔截請求,如認證、CORS、安全檢查。

3. Handler Interceptor:日誌與監控

public class LoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, ...) {
        request.setAttribute("startTime", System.currentTimeMillis());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, ...) {
        Long startTime = (Long) request.getAttribute("startTime");
        long duration = System.currentTimeMillis() - startTime;
        logger.info("Request {} took {}ms", request.getRequestURI(), duration);
    }
}

適用場景:需要在 Controller 方法前後執行邏輯,如日誌記錄、性能監控。

🎯 TY Multiverse 專案實戰應用

各專案中間件使用情況

專案GlobalFilterServlet FilterHandler Interceptor@ControllerAdviceAOP
ty-multiverse-backend✅ (JWT, 限流)✅ (限流)
ty-multiverse-gateway✅ (日誌, CORS, 限流)
ty-multiverse-consumer✅ (CORS)✅ (Reactive)

🔐 JWT 認證架構

Backend 已實現混合認證策略

  • 無狀態服務:JWT 認證(大部分 API)
  • 有狀態服務:Session 認證(CKEditor, DeckOfCards)
  • 認證服務器:Keycloak + OAuth2

🔍 gRPC API 下的責任鏈分析

🎯 關鍵發現

Gateway 層 (HTTP 入口):✅ 中間件完全有效 Backend 層 (gRPC 服務端):❌ 傳統 Servlet Filter/Interceptor 失效

🛠️ gRPC 替代方案

1. gRPC Server Interceptor

public class LoggingServerInterceptor implements ServerInterceptor {
    // 實現 gRPC 級別的日誌、認證、監控
}

2. 應用層中間件

@Service
public class GrpcPeopleServiceImpl extends PeopleServiceGrpc.PeopleServiceImplBase {
    @Override
    public void getAllPeople(...) {
        middlewareChain.process(request, () -> {
            // 業務邏輯
            List<PeopleData> people = peopleService.getAllPeople();
            responseObserver.onNext(buildResponse(people));
            responseObserver.onCompleted();
        });
    }
}

📋 架構建議

防禦性架構:Gateway 做入口防護,Backend 做業務防護

  • Gateway:全域限流、日誌、基本認證
  • Backend:業務權限檢查、數據快取、異常處理

🎓 學習總結

📚 學習路徑建議

  1. 新手階段:掌握 @ControllerAdvice → 學習 Filter → 探索 Interceptor
  2. 進階階段:AOP → Spring Security → Spring Cloud Gateway
  3. 專家階段:自定義中間件框架 → 性能優化 → 分散式追蹤

🏆 最佳實踐

  • 每個中間件只做一件事
  • 統一錯誤響應格式
  • 合理日誌記錄層級
  • 性能監控和測試覆蓋

🔍 常見問題

Q: Filter vs Interceptor? A: Filter 在 Spring 外攔截,能阻止請求進入框架;Interceptor 在 Spring 內,可訪問業務上下文。

Q: gRPC 下中間件失效怎麼辦? A: 使用 gRPC Server Interceptor 替代,並在應用層補償業務邏輯中間件。


本文基於 TY-Multiverse 專案實戰,涵蓋 HTTP/gRPC 雙協議的中間件實現,希望幫助你掌握 Spring Boot 中間件的核心技巧。

TY的智慧庫

你有事?
問前想清楚,機會不是誰都有。

💡 建議主題:

放大圖片