为什么如此高效?解密kryo各个数据类型的序列化编码机制,强( 六 )


DefaultClassResolver#readName
protected Registration readName (Input input) { int nameId = input.readVarInt(true);if (nameIdToClass == null) nameIdToClass = new IntMap(); Class type = nameIdToClass.get(nameId);if (type == null) {// Only read the class name the first time encountered in object graph.String className = input.readString();type = getTypeByName(className);if (type == null) {try {type = Class.forName(className, false, kryo.getClassLoader());} catch (ClassNotFoundException ex) {if (WARN) warn("kryo", "Unable to load class " + className + " with kryo's ClassLoader. Retrying with current..");try {type = Class.forName(className);} catch (ClassNotFoundException e) {throw new KryoException("Unable to find class: " + className, ex);}}if (nameToClass == null) nameToClass = new ObjectMap();nameToClass.put(className, type);}nameIdToClass.put(nameId, type);if (TRACE) trace("kryo", "Read class name: " + className); } else {if (TRACE) trace("kryo", "Read class name reference " + nameId + ": " + className(type)); } return kryo.getRegistration(type);}首先读取类的id , 因为在序列化类时 , 如果序列化字符串时 , 首先先用变长int存储类型的nameId , 然后再序列化类的全路径名 , 这样在一次反序列化时 , 第一次序列化时 , 将全列的全路径使用Class.forName实例化对象后 , 然后存储在局部方法缓存中(IntMap)中 , 在这一次序列化时再碰到同类型时 , 则根据id则可以找到对象 。
类实例序列化总结:
类实例序列化需求:序列化类的全路径名 , 反序列化时根据Class.forName生成对应的实例 。
kryo序列化Class实例的编码规则:

  1. 如果为null , 用变长int , 实际使用1个字节 , 存储变量0 。
  2. 如果该类通过类注册机制注册到kryo时 , 则序列化(nameId + 2) , 用变长int存储 。
  3. 如果该类未通过类注册机制注册到kryo , 在一次序列化过程中(包含级联)时 , 类型第一次出现时 , 会分配一个nameId , 将nameId + type全路径序列化 , 后续再出现该类型 , 则只序列化nameId即可 。
13 , DefaultSerializers $ DateSerializerjava.Util.Date , java.sql.Date等序列化时 , 只需序列化Date#getTime()返回的long类型 , 反序列化时根据long类型创建对应的实例即可 。 long类型的编码使用变长long格式进行序列化 。
14 , 枚举类型Enum序列化实现类为:DefaultSerializers $ EnumSerializer
static public class EnumSerializer extends Serializer {{setImmutable(true);setAcceptsNull(true);}private Object[] enumConstants;public EnumSerializer (Class type) {enumConstants = type.getEnumConstants();if (enumConstants == null) throw new IllegalArgumentException("The type must be an enum: " + type);}public void write (Kryo kryo, Output output, Enum object) {if (object == null) {output.writeVarInt(NULL, true);return;}output.writeVarInt(object.ordinal() + 1, true);}public Enum read (Kryo kryo, Input input, Class type) {int ordinal = input.readVarInt(true);if (ordinal == NULL) return null;ordinal--;if (ordinal < 0 || ordinal > enumConstants.length - 1)throw new KryoException("Invalid ordinal for enum \"" + type.getName() + "\": " + ordinal);Object constant = enumConstants[ordinal];return (Enum)constant;} }枚举类型序列化(支持null):
  1. 如果为null , 则使用变长int , 实际用一个字节存储0 。
  2. 如果不为null , 使用变长int , 存储object.ordinal()+ 1 , 也就是序列化该值在枚举类型常量中中下标 , 由于0代表为空 , 则下标从1开始 。
-在反序列化时 , 通过Enum.class.getEnumConstants()获取枚举类型的常量数组 , 然后从二进制流中获取下标即可 。 -
15 , EnumSet类型序列化实现类为:DefaultSerializers $ EnumSetSerializer
static public class EnumSetSerializer extends Serializer { public void write (Kryo kryo, Output output, EnumSet object) {Serializer serializer;if (object.isEmpty()) {// @1EnumSet tmp = EnumSet.complementOf(object);// @2if (tmp.isEmpty()) throw new KryoException("An EnumSet must have a defined Enum to be serialized.");serializer = kryo.writeClass(output, tmp.iterator().next().getClass()).getSerializer();// @3} else {serializer = kryo.writeClass(output, object.iterator().next().getClass()).getSerializer();}output.writeInt(object.size(), true);// @4for (Object element : object)// @5serializer.write(kryo, output, element);} public EnumSet read (Kryo kryo, Input input, Class type) {Registration registration = kryo.readClass(input);EnumSet object = EnumSet.noneOf(registration.getType());Serializer serializer = registration.getSerializer();int length = input.readInt(true);for (int i = 0; i < length; i++)object.add(serializer.read(kryo, input, null));return object; } public EnumSet copy (Kryo kryo, EnumSet original) {return EnumSet.copyOf(original); }}