1. 程式人生 > >fastjson 始終將 null 物件以 "null " 的形式返回到前端引發的原始碼解析 - 上:從 DispatcherServlet 出發

fastjson 始終將 null 物件以 "null " 的形式返回到前端引發的原始碼解析 - 上:從 DispatcherServlet 出發

背景

專案中使用 fastjson 將 spring MVC 返回結果輸出為 json 格式資料,有個需求是 null 物件不輸出,即前端不會接收到 "obj": null 形式的 json 資料,然而在進行如下的配置後, null 物件始終輸出,因此以閱讀原始碼的方式解決該問題。
image.png

原始碼分析

DispatcherServlet

DispatcherServlet 是 spring MVC 的入口 Servlet,在其 doDispatch 方法中進行 debug 跟蹤就能一步一步跟蹤到 fastjson 的 api 中。

    // Actually invoke the handler.
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

spring mvc 通過 HandlerMapping、HandlerAdapter 定位到最終的處理器方法,ha.handle()方法呼叫的就是我們自己的 controller 層方法,該方法之後會被封裝為 HandlerMethod 物件,再進一步封裝為 ServletInvocableHandlerMethod 型別。

RequestMappingHandlerAdapter

RequestMappingHandlerAdapter#invokeHandlerMethod 方法中會將 controller 層方法包裝為最終的 ServletInvocableHandlerMethod

物件,並進一步呼叫其 invokeAndHandle方法。

ServletInvocableHandlerMethod

這裡有一個 spring mvc 提供的擴充套件點,即 ServletInvocableHandlerMethod 類的 doInvoke(Object... args) 方法,該方法是 spring mvc 真正呼叫 controller 層方法的地方,而實際專案中我們往往在 controller 方法中對入參進行一些校驗,而校驗的這些引數是經過 @RequestParam 或 @RequestBody 註解並處理後的物件,如果要對這些引數進行統一處理,覆寫 doInvoke 方法就是一個不錯的選擇,其中 args 入引數組的元素順序對應 controller 層方法的引數定義順序,在該方法中呼叫 super.doInvoke(args)

得到的即是 controller 層方法的返回值,亦可以對返回值進行統一處理。

舉個栗子:
image.png

之後還有一個步驟是為 spring mvc 提供一個自定義的 RequestMappingHandlerAdapter,在這個 HandlerAdapter 中覆寫獲取 ServletInvocableHandlerMethod 的方法,即 createInvocableHandlerMethod 方法:

@Configuration
public class WebConfig implements WebMvcRegistrations {

    @Override
    public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
        return new RequestMappingHandlerAdapter() {
            @Override
            protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
                return new HandlerMethodResultWrapper(handlerMethod);
            }
        };
    }
}

ServletInvocableHandlerMethod#invokeAndHandle

invokeAndHandle 方法會呼叫一個型別為 HandlerMethodReturnValueHandlerComposite 的成員變數的 handleReturnValue 方法:
image.png

該方法中會從一個 HandlerMethodReturnValueHandler 的 List 中找到能處理當前 controller 返回值的 Handler,然後呼叫其 handleReturnValue 方法處理返回值。

RequestResponseBodyMethodProcessor

該類即為能處理 controller 返回值的 HandlerMethodReturnValueHandler ,最終呼叫到 fastjson 內部 api 的入口在 AbstractMessageConverterMethodProcessor 類的 writeWithMessageConverters 方法中,這裡的類繼承結構如下:RequestResponseBodyMethodProcessor extend AbstractMessageConverterMethodProcessor implements HandlerMethodReturnValueHandler 。

writeWithMessageConverters 方法會從一個型別為 HttpMessageConverter 的 Lsit 中找出配置的轉換器,這裡就會找到 FastJsonHttpMessageConverter,即終於呼叫到了 fastjson 的 api。

接下篇:fastjson 始終將 null 物件以 "null " 的形式返回到前端引發的原始碼解析 - 下:來到 fasjson 內部,消除疑惑