Java序列化的几种方式以及序列化的作用

什么是对象序列化?

 序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程. 
 这是百度百科的说明,也很浅显易懂,比如说,我有一个java对象,我想传输给远端的程序,如何传输尼? 
 java提供了序列化接口,只要实现了Serializable接口,就可将java对象序列化成字节,然后以流的形式传输,然后在远端再反序列化成对象,这就达到了传输消息的目的. 
 但是这种序列化存在一些缺陷,1不能跨语言,2,序列化体积大 
 所以为了支持跨语言,并提高序列效率,减少传输时的码流大小,好多公司或者大神开发了各种序列化库,hession,protostuff,kryo,jackson,xml等,比如json也算是一种序列化,方式,也是目前使用的最为广泛的一种,但是json严格来说并不是一种序列化,它只是一种通用的信息描述方式,一组json信息,可能对应不同的对象模式.比如你可以将一组json转换成java bean对象也可以转换成map,形式具有不确定性.所以一般的远程调用不会采用json来作为序列化实现.

序列类型 是否跨语言 优缺点
hession 支持 跨语言,序列化后体积小,速度较快
protostuff 支持 跨语言,序列化后体积小,速度快,但是需要Schema,可以动态生成
jackson 支持 跨语言,序列化后体积小,速度较快,且具有不确定性
kryo 支持 跨语言支持较困难,序列化后体积小,速度较快
jdk 不支持 序列化后体积很大,速度快

序列化可以做什么?

如第一节提的一样,对象序列化可以用来传输消息,并且以流的形式传输,提高传输效率,使用场景如远程服务调用rpc

各个序列化库比较

0.准备依赖

        <!-- protostuff -->
        <dependency>
            <groupId>com.dyuproject.protostuff</groupId> <artifactId>protostuff-core</artifactId> <version>1.0.8</version> </dependency> <dependency> <groupId>com.dyuproject.protostuff</groupId> <artifactId>protostuff-runtime</artifactId> <version>1.0.8</version> </dependency> <!-- objenesis(support protostuff,可以使用无参构造方法) --> <dependency> <groupId>org.objenesis</groupId> <artifactId>objenesis</artifactId> <version>2.1</version> </dependency> <!-- hessian --> <dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.38</version> </dependency> <!-- jackson --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.5.4</version> </dependency> <!-- kryo --> <dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo</artifactId> <version>4.0.0</version> </dependency>

1.编写序列化接口

public interface Serializer {

    <T> byte[] serialize(T obj);
    <T> Object deserialize(byte[] bytes, Class<T> clazz);
}

2.实现接口

hession实现

public class HessianSerializer implements Serializer { @Override public <T> byte[] serialize(T obj){ ByteArrayOutputStream os = new ByteArrayOutputStream(); HessianOutput ho = new HessianOutput(os); try { ho.writeObject(obj); } catch (IOException e) { throw new IllegalStateException(e.getMessage(), e); } return os.toByteArray(); } @Override public <T> Object deserialize(byte[] bytes, Class<T> clazz) { ByteArrayInputStream is = new ByteArrayInputStream(bytes); HessianInput hi = new HessianInput(is); try { return hi.readObject(); } catch (IOException e) { throw new IllegalStateException(e.getMessage(), e); } } }

jackson实现

public class JacksonSerializer implements Serializer { private final static ObjectMapper objectMapper = new ObjectMapper(); @Override public <T> byte[] serialize(T obj) { try { return objectMapper.writeValueAsBytes(obj); } catch (JsonProcessingException e) { throw new IllegalStateException(e.getMessage(), e); } } @Override public <T> Object deserialize(byte[] bytes, Class<T> clazz) { try { return objectMapper.readValue(bytes, clazz); } catch (JsonParseException e) { throw new IllegalStateException(e.getMessage(), e); } catch (JsonMappingException e) { throw new IllegalStateException(e.getMessage(), e); } catch (IOException e) { throw new IllegalStateException(e.getMessage(), e); } } }

prostfuff实现

public class ProtostuffSerializer implements Serializer { private static Objenesis objenesis = new ObjenesisStd(true); private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>(); private static <T> Schema<T> getSchema(Class<T> cls) { @SuppressWarnings("unchecked") Schema<T> schema = (Schema<T>) cachedSchema.get(cls); if (schema == null) { schema = RuntimeSchema.createFrom(cls); if (schema != null) { cachedSchema.put(cls, schema); } } return schema; } @Override public <T> byte[] serialize(T obj) { @SuppressWarnings("unchecked") 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> Object deserialize(byte[] bytes, Class<T> clazz) { try { T message = (T) objenesis.newInstance(clazz); Schema<T> schema = getSchema(clazz); ProtostuffIOUtil.mergeFrom(bytes, message, schema); return message; } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } } 

kryo实现

public class KryoSerializer implements Serializer { private static final Kryo kryo = new Kryo(); @Override public <T> byte[] serialize(T obj) { try (Output output = new Output(new ByteArrayOutputStream())) { kryo.writeObject(output, obj); byte[] bytes = output.toBytes(); return bytes; } } @Override public <T> Object deserialize(byte[] bytes, Class<T> clazz) { try (Input input = new Input(bytes)) { return kryo.readObject(input, clazz); } } } 

jdk实现

public class JdkSerializer implements Serializer { @Override public <T> byte[] serialize(T obj) { try { ByteArrayOutputStream byteArr = new ByteArrayOutputStream(); ObjectOutputStream out=new ObjectOutputStream(byteArr); out.writeObject(obj); out.flush(); return byteArr.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } @Override public <T> Object deserialize(byte[] bytes, Class<T> clazz) { try { ObjectInputStream input=new ObjectInputStream(new ByteArrayInputStream(bytes)); return input.readObject(); } catch (Exception e) { e.printStackTrace(); } return null; } } 

3,准备序列对象

序列化对象需要实现Serializable,有的需要有的不需要,hession需要,而且还需要有默认的无参构造方法jackson需要

public class User  implements Serializable{ private String name; private String address; private Integer age; public User() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public User(String name, String address, Integer age) { super(); this.name = name; this.address = address; this.age = age; } } 

4.序列化速度比较

public class SerTest {
    public static void main(String[] args) { int len=10; test(new HessianSerializer(), "hession",len); test(new JacksonSerializer(), "jackson",len); test(new ProtostuffSerializer(), "protostu",len); test(new JdkSerializer(),"jdk",len); test(new KryoSerializer(),"kryo",len); } public static void test(Serializer s,String tag,int len){ long cap=0; long sumTime=0; for(int i=0;i<len;i++){ User u=new User("taoyuan"+i, i+"addr", i); long start=System.currentTimeMillis(); byte[] serialize = s.serialize(u); cap+=serialize.length; s.deserialize(serialize, User.class); long cal= System.currentTimeMillis()-start; sumTime+=cal; } System.out.println(tag+"序列总体积大小:"+cap); System.out.println(tag+"序列总消耗时间为:"+sumTime); } } 

结果: 
hession序列总体积大小:780 
hession序列总消耗时间为:172 
jackson序列总体积大小:450 
jackson序列总消耗时间为:166 
protostu序列总体积大小:190 
protostu序列总消耗时间为:127 
jdk序列总体积大小:2140 
jdk序列总消耗时间为:94 
kryo序列总体积大小:180 
kryo序列总消耗时间为:47

5结论

从以上结果来看,序列化综合性能比较好的是protostuff和kryo 
jdk的序列化速度比较快,就是序列体积较大. 
所以当我们的需要开发一套rpc服务时,可以采用kryo来序列化对象,提高传输效率

rpc服务简单实现原理简介

个人理解

要想实现一套rpc服务,首先我们得将我们得从本质理解rpc 
rpc简单来说就是序列化+传输协议+调用实现+服务管理

序列化是基础也决定了rpc是否支持跨语言 
传输协议可以选择tcp,http,udp等协议 
调用实现即rpc服务的业务实现 
服务管理即是在以上基础之上的优化管理层次,负载均衡,调用追踪等

一旦我们从本质上理解了rpc之后,写一套简单的rpc服务也是很简单的事情,具体业务再去分析优化,每一层隔离开,优化时,改动也不会太大,,有机会,我们写一篇,手把手教你实现rpc的博文

猜你喜欢

转载自www.cnblogs.com/zhengshao/p/8882613.html