SpringBoot中如何使用ObjectMapper,老鳥們都是這樣玩的?

帶你聊技術發表於2023-11-21

來源:JAVA日知錄

1. 每次new一個

在SpringBoot專案中要實現物件與Json字串的互轉,每次都需要像如下一樣new 一個ObjectMapper物件:

public UserEntity string2Obj(String json) throws JsonProcessingException {
 ObjectMapper objectMapper = new ObjectMapper();
 return objectMapper.readValue(json, UserEntity.class);
}

public String obj2String(UserEntity userEntity) throws JsonProcessingException {
 ObjectMapper objectMapper = new ObjectMapper();
 return objectMapper.writeValueAsString(car)
}

這樣的程式碼到處可見,有問題嗎?

你要說他有問題吧,確實能正常執行;可你要說沒問題吧,在追求效能的同學眼裡,這屬實算是十惡不赦的程式碼了。

首先,讓我們用JMH對這段程式碼做一個基準測試,讓大家對其效能有個大概的瞭解。

基準測試是指透過設計科學的測試方法、測試工具和測試系統,實現對一類測試物件的某項效能指標進行定量的和可對比的測試。而JMH是一個用來構建,執行,分析Java或其他執行在JVM之上的語言的 納秒/微秒/毫秒/宏觀 級別基準測試的工具。

@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
@Fork(1)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 3, time = 1)
public class JsonJMHTest {
    
    String json = "{\"id\":122345667,\"email\":\"jianzh5@163.com\",\"price\":12.25}";
    UserEntity userEntity = new UserEntity(13345L,"jianzh5@163.com", BigDecimal.valueOf(12.25));
    /**
     * 測試String to Object
     */

    @Benchmark
    public UserEntity objectMapper2ObjTest() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(json, UserEntity.class);
    }

    /**
     * 測試Object to String
     */

    @Benchmark
    public String objectMapper2StringTest() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.writeValueAsString(userEntity);
    }
  
   public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JsonJMHTest.class.getSimpleName())
                .build()
;
        new Runner(opt).run();
    }
}

測試環境

# JMH version: 1.36
# VM version: JDK 17.0.3, OpenJDK 64-Bit Server VM, 17.0.3+7-LTS
# Mac AppleM1/16GB

測試結果

SpringBoot中如何使用ObjectMapper,老鳥們都是這樣玩的?

透過測試結果可以看出,每次new一個ObjectMapper,在實現字串轉物件時每秒可以完成23萬多次,而實現物件轉Json字串每秒僅可完成2.7萬次。

SpringBoot中如何使用ObjectMapper,老鳥們都是這樣玩的?

那該如何最佳化,提升效能呢?

2. 單例化

老鳥們都知道,在建立工具類時要將工具類設定成單例的,這樣不僅可以保證執行緒安全,也可以保證在系統全域性只能建立一個物件,避免頻繁建立物件的成本。

所以,我們可以在專案中構建一個ObjectMapper的單例類。

@Getter
public enum ObjectMapperInstance {
    
    INSTANCE;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    ObjectMapperInstance() {
        
    }
}

再次使用JMH對其測試:

@Benchmark
public UserEntity singleten2ObjTest() throws JsonProcessingException {
  ObjectMapper objectMapper = ObjectMapperInstance.INSTANCE.getObjectMapper();
  return objectMapper.readValue(json, UserEntity.class);
}

@Benchmark
public String singleten2StringTest() throws JsonProcessingException {
  ObjectMapper objectMapper = ObjectMapperInstance.INSTANCE.getObjectMapper();
  return objectMapper.writeValueAsString(userEntity);
}

測試結果如下:

SpringBoot中如何使用ObjectMapper,老鳥們都是這樣玩的?

可以看到,使用單例模式,String轉物件的方法每秒可以執行420多萬次,比new ObjectMapper的方式快了18倍;而物件轉String的方法每秒可以執行830萬次,效能提升了300倍(看到結果的一瞬間我傻眼了,一度懷疑是寫錯程式碼了)!!!!

SpringBoot中如何使用ObjectMapper,老鳥們都是這樣玩的?

3. 個性化配置

當然,在專案中使用ObjectMapper時,有時候我們還需要做一些個性化配置,比如將Long和BigDemical型別的屬性都透過字串格式進行轉換,防止前端使用時丟失數值精度。

這些型別轉換的格式對映都可以在單例類中配置,程式碼如下:

@Getter
public enum ObjectMapperInstance {
    
    INSTANCE;
    
    private final ObjectMapper objectMapper;
    
    ObjectMapperInstance() {
        objectMapper = new ObjectMapper();
        // 註冊自定義模組
        initialize();
    }
    
    private void initialize() {
        CustomJsonModule customJsonModule = new CustomJsonModule();
        objectMapper.registerModule(customJsonModule);
    }
}

在initialize()方法中給ObjectMapper註冊自定義序列化轉換器。

SpringBoot中如何使用ObjectMapper,老鳥們都是這樣玩的?

第一行是使用註冊自定義序列換轉換器後的效果,給id和price欄位都加上了引號。

再來一次JMH測試:

SpringBoot中如何使用ObjectMapper,老鳥們都是這樣玩的?

可以看到,給ObjectMapper額外註冊轉換型別以後效能會受到一定的影響,但對業務影響不大。(啥業務能這麼高的請求~)

4. 小結

透過上面的測試,結論已經很清晰了。使用單例模式進行字串轉物件時效能可以提升18倍,而物件轉String效能快了驚人的290萬倍,所以在Spring中如何正確的使用ObjectMapper不用我再說了吧~

DailyMart是一個基於領域驅動設計(DDD)和Spring Cloud Alibaba的微服務商城系統。我們將在該系統中整合博主其他專欄文章的核心內容。如果你對這兩大技術棧感興趣,可以在本公眾號回覆關鍵詞 DDD 以獲取相關原始碼。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2996283/,如需轉載,請註明出處,否則將追究法律責任。

相關文章