实现 序列化引擎(支持 JDK默认、Hessian、Json、Protostuff、Xml、Avro、ProtocolBuffer、Thrift等序列化方式)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/alinyua/article/details/84201285

本文将实现一个包含JDK默认、Hessian、Json、Protostuff、Xml、Avro、ProtocolBuffer、Thrift等序列化方式的序列化引擎。用户可以提供使用 SerializerEngine 方便快捷地切换序列化方法实现。

一 使用效果

执行代码如下:

    @Data
    public static class Person {
        String name;
        int age;
        Date birth;
    }

    public static void main(String[] args){
        Person person=new Person();
        person.setName("li");
        person.setAge(18);
        person.setBirth(new Date());
        out.println(person);
        out.println("--------- Json序列化 ------------");
        byte[] personBytes=SerializerEngine.serialize(person, SerializeTypeEnum.JSONSerializer);
        out.println(new String(personBytes));
        out.println("--------- Json反序列化 ---------------------");
        person=SerializerEngine.deserialize(personBytes,Person.class,SerializeTypeEnum.JSONSerializer);
        out.println(person);
        out.println("---------- Xml序列化  -------------------");
        personBytes=SerializerEngine.serialize(person, SerializeTypeEnum.XmlSerializer);
        out.println(new String(personBytes));
        out.println("---------- Xml反序列化 ------------------");
        person=SerializerEngine.deserialize(personBytes,Person.class,SerializeTypeEnum.XmlSerializer);
        out.println(person);

    }

结果为:
结果

二 总体结构

1 结构图

结构

2 组件介绍

  • ISerializer (序列化接口)
    定义序列化和反序列化方法
  • impl (序列化接口实现类)
    实现序列化和反序列化方法
  • SerializeTypeEnum (序列化枚举类)
    一个不重复的数字code对应一个枚举类
  • SerializerEngine (序列化引擎)
    管理序列化枚举类和实现类的对应关系,并提供通用序列化与反序列化方法入口

序列化方法分类

  1. 不需要 IDL 工具
    1. 需有Serializable接口
      • DefaultJavaSerializer
      • HessianSerializer
    2. 不需有Serializable接口
      • JSONSerializer
      • XmlSerializer
      • ProtoStuffSerializer
  2. 需要 IDL 工具
    • AvroSerializer
    • ThriftSerializer
    • ProtocolBufferSerializer

序列化方法场景推荐

如果不使用IDL的服务间传输的话,建议使用 ProtoStuffSerializer ,如果有可读性要求或是基于Ajax和移动APP通信的话就使用 JSONSerializer。

3 相互关系

用户直接使用 SerializerEngine 进行序列化和反序列化,通过传入 SerializeTypeEnum 指定序列化方法,SerializeTypeEnum和序列化方法的关系由 SerializerEngine 维护,序列化方法实现类实例 由SerializerEngine保存和管理。

三 结构实现

1 ISerializer

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 18-11-12
 * @Description: 序列化接口
 */
public interface ISerializer {

    /**
     * 序列化
     * @param obj 序列化对象
     * @param <T> 序列化对象原始类型
     * @return 字节数组
     */
     <T> byte[] serialize(T obj);


    /**
     * 反序列化
     * @param data 序列化字节数组
     * @param clazz 原始类型的类对象
     * @param <T> 原始类型
     * @return
     */
     <T> T deserialize(byte[] data, Class<T> clazz);
}

2 SerializeTypeEnum

注意这里每种序列化方式都对应了一个数字

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 18-11-18
 * @Description: 序列化枚举类
 */
public enum SerializeTypeEnum {
    /**
     * Java默认序列化
     */
    DefaultJavaSerializer(0),
    /**
     * Hessian序列化
     */
    HessianSerializer(1),
    /**
     * Json序列化(基于Jackson)
     */
    JSONSerializer(2),
    /**
     * Protostuff序列化
     */
    ProtoStuffSerializer(3),
    /**
     * Xml序列化
     */
    XmlSerializer(4),
    /**
     * Avro序列化,需借助IDL
     */
    AvroSerializer(5),
    /**
     * ProtocolBuffer序列化,需借助IDL
     */
    ProtocolBufferSerializer(6),
    /**
     * Thrift序列化,需借助IDL
     */
    ThriftSerializer(7);

    private int code;

    SerializeTypeEnum(int code) {
        this.code = code;
    }

    public static SerializeTypeEnum queryByCode  (int code) {
        for (SerializeTypeEnum type : values()) {
            if(type.getCode()==code){
                return type;
            }
        }
        return null;
    }

    public int getCode() {
        return code;
    }

}

3 SerializerEngine

利用 SERIALIZER_MAP 管理 枚举和实现类的关系,提供可以指定序列化类型的入口方法

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 18-11-18
 * @Description: 序列化引擎
 */
public class SerializerEngine {

    private static final Map<SerializeTypeEnum, ISerializer> SERIALIZER_MAP = Maps.newConcurrentMap();

    static {
        SERIALIZER_MAP.put(SerializeTypeEnum.DefaultJavaSerializer, new DefaultJavaSerializer());
        SERIALIZER_MAP.put(SerializeTypeEnum.HessianSerializer, new HessianSerializer());
        SERIALIZER_MAP.put(SerializeTypeEnum.JSONSerializer, new JSONSerializer());
        SERIALIZER_MAP.put(SerializeTypeEnum.XmlSerializer, new XmlSerializer());
        SERIALIZER_MAP.put(SerializeTypeEnum.ProtoStuffSerializer, new ProtoStuffSerializer());

        //以下三类不能使用普通的java bean,需借助IDL
        SERIALIZER_MAP.put(SerializeTypeEnum.AvroSerializer, new AvroSerializer());
        SERIALIZER_MAP.put(SerializeTypeEnum.ThriftSerializer, new ThriftSerializer());
        SERIALIZER_MAP.put(SerializeTypeEnum.ProtocolBufferSerializer, new ProtocolBufferSerializer());
    }

    public static <T> byte[] serialize(T obj, SerializeTypeEnum serializeTypeEnum) {

        ISerializer serializer = SERIALIZER_MAP.get(serializeTypeEnum);
        return serializer.serialize(obj);
    }
    
    public static <T> T deserialize(byte[] data, Class<T> clazz, SerializeTypeEnum serializeTypeEnum) {

        ISerializer serializer = SERIALIZER_MAP.get(serializeTypeEnum);
        return serializer.deserialize(data, clazz);

    }
    
}

四 各种序列化方法实现

1 DefaultJavaSerializer

效率低,局限于Java

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 18-11-18
 * @Description: Java默认序列化(需有Serializable接口)
 */
public class DefaultJavaSerializer implements ISerializer {


    @Override
    public <T> byte[] serialize(T obj) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)){
            objectOutputStream.writeObject(obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return byteArrayOutputStream.toByteArray();
    }


    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) {

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return (T) objectInputStream.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

2 HessianSerializer

使用方法和DefaultJavaSerializer类似,但效率高,而且跨语言,在大部分场景下可取代DefaultJavaSerializer(在某些情况下支持没有Java原生的好)

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 18-11-18
 * @Description: Hessian序列化(需有Serializable接口)
 */
public class HessianSerializer implements ISerializer {


    @Override
    public byte[] serialize(Object obj) {
        try(ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            HessianOutput ho = new HessianOutput(os);
            ho.writeObject(obj);
            return os.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) {

        try(ByteArrayInputStream is = new ByteArrayInputStream(data)) {
            HessianInput hi = new HessianInput(is);
            return (T) hi.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        
    }

}

3 JSONSerializer

跨语言,可读性好,效率相对没那么高,这里用Jackson实现,可以完成很多定制

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 18-11-18
 * @Description: Json序列化(基于jackson实现)
 */
public class JSONSerializer implements ISerializer {

    /**
     * ObjectMapper可配置json序列化规则,该类的创建需要消耗较多资源,故应配置为类成员对象
     */
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        //允许字段名不带引号(这不符合JSON标准,但在JS中合法)
        OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        //允许使用单引号代替双引号(这不符合JSON标准,但这一些JSON生成器中合法)
        OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        //允许携带不加引号的控制字符(即ASCII码小于32的),不符合JSON标准,故默认为false
        OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        //允许出现未定义处理方法(没有对应的setter方法或其他的处理器)的未知字段
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public <T> byte[] serialize(T obj) {
        try {
            String json = OBJECT_MAPPER.writeValueAsString(obj);
            return json.getBytes();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) {
        String json = new String(data);
        try {
            return (T) OBJECT_MAPPER.readValue(json, clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

4 XmlSerializer

大部分情况下可被Json取代

/**
 * @author liyebing created on 17/1/21.
 * @version $Id$
 */
public class XmlSerializer implements ISerializer {

    private static final XStream xStream = new XStream(new DomDriver());
    
    @Override
    public <T> byte[] serialize(T obj) {
        return xStream.toXML(obj).getBytes();
    }
    
    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) {
        String xml = new String(data);
        return (T) xStream.fromXML(xml);
    }
    
}

5 ProtoStuffSerializer

基于protostuff的protocolbuffer序列化工具,各方面效率都高,且不需要借助IDL(接口描述语言)

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 2018/11/18
 * @Description: protobuf序列化工具(基于protostuff)
 */
public class ProtoStuffSerializer implements ISerializer {

    /**
     * 用于缓存类对象与Schema的对应关系,避免重复创建Schema
     */
    private static final Map<Class<?>, Schema<?>> CACHED_SCHEMA = new ConcurrentHashMap<>();

    /**
     * 用于高效便捷地生成类实例,而无需构造方法支持
     */
    private static final Objenesis OBJENESIS = new ObjenesisStd(true);

    /**
     * 序列化(对象 -> 字节数组)
     */
    @Override
    @SuppressWarnings("unchecked")
    public  <T> byte[] serialize(T obj) {
        Class<T> cls = (Class<T>) obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            Schema<T> schema = getSchema(cls);
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            buffer.clear();
        }
    }

    /**
     * 反序列化(字节数组 -> 对象)
     */
    @Override
    public  <T> T deserialize(byte[] data, Class<T> cls) {
        try {
            T message = OBJENESIS.newInstance(cls);
            Schema<T> schema = getSchema(cls);
            ProtostuffIOUtil.mergeFrom(data, message, schema);
            return message;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    @SuppressWarnings("unchecked")
    private  <T> Schema<T> getSchema(Class<T> cls) {
        Schema<T> schema = (Schema<T>) CACHED_SCHEMA.get(cls);
        if (schema == null) {
            schema = RuntimeSchema.createFrom(cls);
            CACHED_SCHEMA.put(cls, schema);
        }
        return schema;
    }
}

6 AvroSerializer

需要借助IDL

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 2018/11/18
 * @Description: AvroSerializer(只能序列化IDL产生的类)
 */
public class AvroSerializer implements ISerializer {

    @Override
    public <T> byte[] serialize(T obj) {
        try {
            DatumWriter userDatumWriter = new SpecificDatumWriter(obj.getClass());
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            BinaryEncoder binaryEncoder = EncoderFactory.get().directBinaryEncoder(outputStream, null);
            userDatumWriter.write(obj, binaryEncoder);
            return outputStream.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) {
        try {
            DatumReader userDatumReader = new SpecificDatumReader(clazz);
            BinaryDecoder binaryDecoder = DecoderFactory.get().directBinaryDecoder(new ByteArrayInputStream(data), null);
            return (T) userDatumReader.read(clazz.newInstance(), binaryDecoder);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

}

7 ThriftSerializer

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 2018/11/18
 * @Description: Thrift序列化(只能序列化IDL产生的类)
 */
public class ThriftSerializer implements ISerializer {
    
    @Override
    public <T> byte[] serialize(T obj) {
        try {
            TSerializer serializer = new TSerializer(new TBinaryProtocol.Factory());
            return serializer.serialize((TBase) obj);
        } catch (TException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) {
        try {
            TBase o = (TBase) clazz.newInstance();
            TDeserializer tDeserializer = new TDeserializer();
            tDeserializer.deserialize(o, data);
            return (T) o;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

}

8 ProtocolBufferSerializer

/**
 * @version V1.0
 * @author: lin_shen
 * @date: 2018/11/18
 * @Description: ProtocolBuffer序列化(只能序列化IDL产生的类)
 */
public class ProtocolBufferSerializer implements ISerializer {
    
    @Override
    public <T> byte[] serialize(T obj) {
        try {
            return (byte[]) MethodUtils.invokeMethod(obj, "toByteArray");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public <T> T deserialize(byte[] data, Class<T> cls) {
        try {
            Object o = MethodUtils.invokeStaticMethod(cls, "getDefaultInstance");
            return (T) MethodUtils.invokeMethod(o, "parseFrom", new Object[]{data});
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

猜你喜欢

转载自blog.csdn.net/alinyua/article/details/84201285