作者:fredalxin
地址:https://fredal.xin/kryo-quickstart
Kryo是一个高性能的序列化/反序列化工具,由于其变长存储特性并使用了字节码生成机制,拥有较高的运行速度和较小的体积,在某些场景中成为了除Json、Protobuf之外的选择。
依赖
首先我们引入maven的相关依赖:
<dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo</artifactId> <version>4.0.2</version></dependency>
需要注意的是,由于kryo使用了较高版本的asm,可能会与业务现有依赖的asm产生冲突,这是一个比较常见的问题。只需将依赖改成:
<dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo-shaded</artifactId> <version>4.0.2</version></dependency>
记录类型信息
这算是kryo的一个特点,可以把对象信息直接写到序列化数据里,反序列化的时候可以精确地找到原始类信息,不会出错,这意味着在写readxxx方法时,无需传入Class或Type类信息。
相应的,kryo提供两种读写方式。记录类型信息的writeClassAndObject/readClassAndObject方法,以及传统的writeObject/readObject方法。
线程安全
kryo的对象本身不是线程安全的,所以我们有两种选择来保障线程安全。
使用Threadlocal来保障线程安全:
private static final ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>() { protected Kryo initialValue() { Kryo kryo = new Kryo(); kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy( new StdInstantiatorStrategy())); return kryo; };};
或者使用kryo提供的pool:
public KryoPool newKryoPool() { return new KryoPool.Builder(() -> { final Kryo kryo = new Kryo(); kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy( new StdInstantiatorStrategy())); return kryo; }).softReferences().build();}
实例化器
在上面注意到kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
这句话显示指定了实例化器。
在一些依赖了kryo的开源软件中,可能由于实例化器指定的问题而抛出空指针异常。例如hive的某些版本中,默认指定了StdInstantiatorStrategy。
public static ThreadLocal<Kryo> runtimeSerializationKryo = new ThreadLocal<Kryo>() { @Override protected synchronized Kryo initialValue() { Kryo kryo = new Kryo(); kryo.setClassLoader(Thread.currentThread().getContextClassLoader()); kryo.register(java.sql.Date.class, new SqlDateSerializer()); kryo.register(java.sql.Timestamp.class, new TimestampSerializer()); kryo.register(Path.class, new PathSerializer()); kryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); ...... return kryo; };};
而StdInstantiatorStrategy在是依据JVM version信息及JVM vendor信息创建对象的,可以不调用对象的任何构造方法创建对象。
那么例如碰到ArrayList这样的对象时候,就会出问题。观察一下ArrayList的源码:
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
既然没有调用构造器,那么这里elementData会是NULL,那么在调用类似ensureCapacity方法时,就会抛出一个异常。
public void ensureCapacity(int minCapacity) { if (minCapacity > elementData.length && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA && minCapacity <= DEFAULT_CAPACITY)) { modCount++; grow(minCapacity); } }
解决方案很简单,就如框架中代码写的一样,显示指定实例化器,首先使用默认无参构造策略DefaultInstantiatorStrategy,若创建对象失败再采用StdInstantiatorStrategy。
类注册
当kryo写一个对象的实例的时候,默认需要将类的完全限定名称写入。将类名一同写入序列化数据中是比较低效的,所以kryo支持通过类注册进行优化。
kryo.register(SomeClassA.class);kryo.register(SomeClassB.class);kryo.register(SomeClassC.class);
注册会给每一个class一个int类型的Id相关联,这显然比类名称高效,但同时要求反序列化的时候的Id必须与序列化过程中一致。这意味着注册的顺序非常重要。
但是由于现实原因,同样的代码,同样的Class在不同的机器上注册编号任然不能保证一致,所以多机器部署时候反序列化可能会出现问题。
所以kryo默认会禁止类注册,当然如果想要打开这个属性,可以通过kryo.setRegistrationRequired(true);
打开。
循环引用
这是对循环引用的支持,可以有效防止栈内存......
原文转载:http://www.shaoqun.com/a/833907.html
跨境电商:https://www.ikjzd.com/
跨境通网站:https://www.ikjzd.com/w/1329
upc:https://www.ikjzd.com/w/111
抢注商标:https://www.ikjzd.com/w/1053
作者:fredalxin地址:https://fredal.xin/kryo-quickstartKryo是一个高性能的序列化/反序列化工具,由于其变长存储特性并使用了字节码生成机制,拥有较高的运行速度和较小的体积,在某些场景中成为了除Json、Protobuf之外的选择。依赖首先我们引入maven的相关依赖:<dependency><groupId>com.esoteri
yiqu:https://www.ikjzd.com/w/210
首信易支付:https://www.ikjzd.com/w/1841
全方位揭秘!什么是亚马逊的Amazon global store?:https://www.ikjzd.com/articles/21977
图文详解:亚马逊账户信用卡信息更换实操:https://www.ikjzd.com/articles/21978
跨境电商小白必看!询盘如何成功转化成订单?:https://www.ikjzd.com/articles/21979
Jumia卖家注意:平台物流放假公告请查收!:https://www.ikjzd.com/articles/21981
女朋友越来越会叫 她快高潮时故意拔出来:http://www.30bags.com/m/a/249922.html
妈妈说一周一次 姐今天晚上就是你的人:http://www.30bags.com/m/a/249789.html
人渣!首尔大学音乐系的一名教授多次对他的研究生进行性骚扰和威胁:http://lady.shaoqun.com/a/390519.html
持续性全身疼痛和感觉减退——可能是脊髓空孔疾病:http://lady.shaoqun.com/a/390520.html
肾结石曾经疼过一次,后来不疼就治好了?医生:也许斯通已经长大了:http://lady.shaoqun.com/a/390522.html
Lazada入驻条件费用&Lazada中国卖家入驻有优势吗?:https://www.ikjzd.com/articles/146098
No comments:
Post a Comment