基于對象池模式的 JSON 處理性能提升實踐
前言
在應用開發過程中,我們經常會遇到對象的頻繁創建和銷毀操作。以Jackson 庫中的ObjectMapper為例,它用于JSON與Java對象之間的序列化和反序列化,在處理大量JSON數據時,若每次使用都實例化一個新的ObjectMapper對象,不僅會消耗大量系統資源,還會帶來顯著的性能損耗。
實例化問題分析
public class JsonUtils {
public static String toJson(Object obj) {
try {
// 每次調用都創建新的ObjectMapper實例
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static <T> T fromJson(String json, Class<T> clazz) {
try {
// 每次調用都創建新的ObjectMapper實例
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}ObjectMapper是Jackson庫的核心類,負責處理Java對象和JSON之間的轉換工作。然而,ObjectMapper的實例化過程并非輕量級操作,它需要進行一系列的初始化工作,包括配置默認的序列化和反序列化規則、加載插件等。當在高并發場景下,頻繁地實例化ObjectMapper對象,會產生以下問題:
- 性能損耗:每次實例化
ObjectMapper都需要消耗CPU和內存資源,尤其是在短時間內大量實例化時,會導致系統性能下降,響應時間變長。 - 垃圾回收壓力:頻繁創建和銷毀
ObjectMapper對象,會使Java虛擬機(JVM)的垃圾回收機制頻繁工作,占用大量的CPU時間,影響系統的整體吞吐量。
對象池模式簡介
對象池模式(Object Pool Pattern)是一種創建型設計模式,它的核心思想是在系統初始化時預先創建一定數量的對象,并將這些對象存放在一個池子中。當系統需要使用該對象時,直接從對象池中獲取,使用完畢后再將對象放回池中,而不是每次都重新創建和銷毀對象。通過這種方式,可以減少對象創建和銷毀的開銷,提高系統的性能和資源利用率,對象池模式適用于以下場景:
- 對象的創建和銷毀過程比較復雜、開銷較大。
- 對象的使用頻率較高,且生命周期較短。
- 系統對性能和資源利用率有較高的要求。
設計 ObjectMapper 對象池
- 初始化對象池:在系統啟動時,創建一定數量的
ObjectMapper對象,并將它們放入對象池中。 - 獲取對象:從對象池中獲取一個可用的
ObjectMapper對象,如果對象池為空,則根據需要創建新的對象。 - 歸還對象:使用完畢后,將
ObjectMapper對象歸還到對象池中,以便后續使用。
實現 ObjectMapper 對象池
public class ObjectMapperPool {
private static final int POOL_SIZE = 10;
private final Queue<ObjectMapper> objectMapperQueue;
public ObjectMapperPool() {
objectMapperQueue = new LinkedList<>();
initializePool();
}
private void initializePool() {
for (int i = 0; i < POOL_SIZE; i++) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapperQueue.add(objectMapper);
}
}
public ObjectMapper borrowObjectMapper() {
if (objectMapperQueue.isEmpty()) {
return new ObjectMapper();
}
return objectMapperQueue.poll();
}
public void returnObjectMapper(ObjectMapper objectMapper) {
objectMapperQueue.add(objectMapper);
}
}使用 ObjectMapper 對象池
public class JsonUtil {
private static final ObjectMapperPool objectMapperPool = new ObjectMapperPool();
public static String toJson(Object object) {
try {
ObjectMapper objectMapper = objectMapperPool.borrowObjectMapper();
String json = objectMapper.writeValueAsString(object);
objectMapperPool.returnObjectMapper(objectMapper);
return json;
} catch (Exception e) {
throw new RuntimeException("Failed to convert object to JSON", e);
}
}
public static <T> T fromJson(String json, Class<T> clazz) {
try {
ObjectMapper objectMapper = objectMapperPool.borrowObjectMapper();
T result = objectMapper.readValue(json, clazz);
objectMapperPool.returnObjectMapper(objectMapper);
return result;
} catch (Exception e) {
throw new RuntimeException("Failed to convert JSON to object", e);
}
}
}進階版
common-pool2是Apache開源的對象池管理工具,相比自行實現簡單的對象池,它具備諸多優勢:
- 功能豐富:提供了對象創建、激活、銷毀、空閑檢測等全生命周期管理功能,支持靈活配置對象池參數。
- 性能優越:通過高效的資源管理算法,減少資源爭奪,提升并發性能,降低系統開銷。
- 線程安全:內部實現充分考慮多線程環境,確保在高并發場景下對象池操作的線程安全性,無需開發者額外進行復雜的同步處理。
定義 ObjectMapper 對象工廠
public class ObjectMapperFactory implements PooledObjectFactory<ObjectMapper> {
@Override
public ObjectMapper create() throws Exception {
return new ObjectMapper();
}
@Override
public PooledObject<ObjectMapper> wrap(ObjectMapper objectMapper) {
return new DefaultPooledObject<>(objectMapper);
}
@Override
public void destroyObject(PooledObject<ObjectMapper> pooledObject) throws Exception {
// 若ObjectMapper有資源清理操作,可在此執行,一般無需特殊處理
}
@Override
public boolean validateObject(PooledObject<ObjectMapper> pooledObject) {
return pooledObject.getObject() != null;
}
@Override
public void activateObject(PooledObject<ObjectMapper> pooledObject) throws Exception {
// 激活對象時的操作,通常無需特殊處理
}
@Override
public void passivateObject(PooledObject<ObjectMapper> pooledObject) throws Exception {
// 鈍化對象時的操作,如重置ObjectMapper配置,一般無需特殊處理
}
}create方法負責創建新的ObjectMapper實例。wrap方法將創建的對象包裝成PooledObject,便于common-pool2管理。destroyObject定義對象銷毀邏輯,對于ObjectMapper一般無需特殊清理。validateObject用于驗證對象是否可用,這里通過簡單的序列化操作進行判斷。activateObject和passivateObject分別處理對象激活和鈍化時的操作,通常情況下保持默認即可。
配置并使用 ObjectMapper 對象池
public class ObjectMapperPool {
private static final GenericObjectPool<ObjectMapper> objectMapperPool;
static {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
// 設置對象池參數
config.setMaxTotal(20); // 最大對象數
config.setMaxIdle(10); // 最大空閑對象數
config.setMinIdle(5); // 最小空閑對象數
config.setBlockWhenExhausted(true); // 當池耗盡時,請求線程是否阻塞等待
config.setMaxWaitMillis(3000); // 最大等待時間(毫秒)
ObjectMapperFactory factory = new ObjectMapperFactory();
objectMapperPool = new GenericObjectPool<>(factory, config);
}
public static ObjectMapper borrowObjectMapper() {
try {
return objectMapperPool.borrowObject();
} catch (Exception e) {
throw new RuntimeException("Failed to borrow ObjectMapper", e);
}
}
public static void returnObjectMapper(ObjectMapper objectMapper) {
objectMapperPool.returnObject(objectMapper);
}
}- 通過靜態代碼塊配置
GenericObjectPoolConfig,設置對象池的關鍵參數,如最大對象數、空閑對象數等,以適應不同的業務場景和系統資源情況。 - 基于配置和
ObjectMapperFactory創建GenericObjectPool實例,用于管理ObjectMapper對象。 borrowObjectMapper方法從對象池中獲取ObjectMapper對象,若獲取失敗則拋出異常。returnObjectMapper方法將使用完畢的對象歸還到對象池。
最終版
在Java中,枚舉類型天然是線程安全的,并且在類加載時就會完成實例化,保證了單例的唯一性。
@Getter
public enum ObjectMapperInstance {
INSTANCE;
private final ObjectMapper objectMapper = new ObjectMapper();
ObjectMapperInstance() {
}
}























