Protostuff 深度解析:高性能 Java 序列化方案

1:依赖

    implementation "io.protostuff:protostuff-core:1.8.0"
    implementation "io.protostuff:protostuff-runtime:1.8.0"

2:代码

package tech.tongyu.etrade.trsmanager.utils;

import cn.hutool.core.collection.CollUtil;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.runtime.RuntimeSchema;
import org.apache.commons.lang3.SerializationUtils;
import tech.tongyu.etrade.trsmanager.feign.DTO.PriceChangeRankingItemDTO;
import tech.tongyu.idp.model.SecurityExchange;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@SuppressWarnings("unchecked")
public class ProtostuffUtils {

    /** Schema 缓存 */
    private static final Map<Class<?>, RuntimeSchema<?>> SCHEMA_CACHE = new ConcurrentHashMap<>();

    /** 每个线程复用一个 buffer —— 性能最优 */
    private static final ThreadLocal<LinkedBuffer> BUFFER_LOCAL = ThreadLocal.withInitial(() -> LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));

    /** 获取 schema(带缓存) */
    private static <T> RuntimeSchema<T> getSchema(Class<T> clazz) {
        return (RuntimeSchema<T>) SCHEMA_CACHE.computeIfAbsent(clazz, RuntimeSchema::createFrom);
    }

    /** Protostuff 单对象序列化 */
    public static <T> byte[] serialize(T obj) {
        if (obj == null) return new byte[0];
        Class<T> clazz = (Class<T>) obj.getClass();
        RuntimeSchema<T> schema = getSchema(clazz);
        LinkedBuffer buffer = BUFFER_LOCAL.get();
        try {
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } finally {
            buffer.clear();
        }
    }

    /** Protostuff 单对象反序列化 */
    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        if (data == null || data.length == 0) return null;
        RuntimeSchema<T> schema = getSchema(clazz);
        T obj = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(data, obj, schema);
        return obj;
    }


    /** Protostuff list 列表序列化 */
    public static <T> byte[] serializeList(List<T> list) {
        if (CollUtil.isEmpty(list)) return new byte[0];

        Class<T> clazz = (Class<T>) list.get(0).getClass();
        RuntimeSchema<T> schema = getSchema(clazz);
        LinkedBuffer buffer = BUFFER_LOCAL.get();
        // 预估大小(减少扩容开销)
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(Math.max(512, list.size() * 64));

        try {
            ProtostuffIOUtil.writeListTo(outputStream, list, schema, buffer);
            return outputStream.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("Protostuff 列表序列化失败", e);
        } finally {
            buffer.clear();
        }
    }

    /** Protostuff list 列表反序列化 */
    public static <T> List<T> deserializeList(byte[] data, Class<T> clazz) {
        if (data == null || data.length == 0) return Collections.emptyList();
        RuntimeSchema<T> schema = getSchema(clazz);
        try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
            return ProtostuffIOUtil.parseListFrom(bais, schema);
        } catch (IOException e) {
            throw new RuntimeException("Protostuff 列表反序列化失败", e);
        }
    }
}



3:测试 53000 条数据

    public static void main(String[] args) {

        List<PriceChangeRankingItemDTO> list = new ArrayList<>();
        for (int i = 0; i < 53000; i++) {
            PriceChangeRankingItemDTO itemDTO = new PriceChangeRankingItemDTO();
            itemDTO.setSecurityId("000001.XSHE");
            itemDTO.setSecurityExchange(SecurityExchange.SH);
            itemDTO.setLatestPrice(new BigDecimal("10.0"));
            itemDTO.setPriceChangePercentage(new BigDecimal("0.1"));
            list.add(itemDTO);
        }

        // -------- 序列化耗时 --------
        long t1 = System.nanoTime();
        byte[] bytes = serializeList(list);
        long t2 = System.nanoTime();

        // -------- 反序列化耗时 --------
        long t3 = System.nanoTime();
        List<PriceChangeRankingItemDTO> list1 = deserializeList(bytes, PriceChangeRankingItemDTO.class);
        long t4 = System.nanoTime();

        long t5 = System.nanoTime();
        byte[] serialize = SerializationUtils.serialize((Serializable) list);
        long t6 = System.nanoTime();
        long t7 = System.nanoTime();
        Object deserialize = SerializationUtils.deserialize(serialize);
        long t8 = System.nanoTime();

        System.out.println("序列化耗时: " + (t2 - t1) / 1_000_000.0 + " ms");
        System.out.println("反序列化耗时: " + (t4 - t3) / 1_000_000.0 + " ms");

        System.out.println("SerializationUtils 序列化耗时: " + (t6 - t5) / 1_000_000.0 + " ms");
        System.out.println("SerializationUtils 反序列化耗时: " + (t8 - t7) / 1_000_000.0 + " ms");


        System.out.println("list1 size = " + list1.size());

4:测试截图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大大怪~将军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值