【问题标题】:How to serialize Exception object using Kyro?如何使用 Kyro 序列化异常对象?
【发布时间】:2015-12-22 06:16:34
【问题描述】:

我有以下自定义异常,我需要使用 kryo 库对其进行序列化。

public class CustomException extends Exception {
 public CustomException(){}
}

这是我的序列化器

Kryo kryo = new Kryo();
kryo.writeClassAndObject(out, obj);

但是序列化会引发以下异常。

com.esotericsoftware.kryo.KryoException: Class cannot be created (missing no-arg constructor):    java.util.Collections$UnmodifiableRandomAccessList
Serialization trace:
suppressedExceptions (CustomException)
at      com.esotericsoftware.kryo.Kryo$DefaultInstantiatorStrategy.newInstantiatorOf(      Kryo.java:1272)
    at com.esotericsoftware.kryo.Kryo.newInstantiator(Kryo.java:1078)

我已经用JavaSerializer注册CustomException解决了这个问题

 kryo.register(CustomException.class, new JavaSerializer());

但是由于JavaSerializer 效率非常低(建议避免在JavaSerializer javadoc 中尽可能使用),还有其他方法可以在kryo 中序列化异常对象吗?

【问题讨论】:

  • 你已经抛出了一个比 Java 序列化器效率低的异常。除非您的应用程序经常抛出很多异常,否则我认为尝试自定义它没有意义。
  • 我遇到了同样的问题...你是怎么解决这个问题的?
  • 使用JavaSerializer,正如我在问题中所说的那样。

标签: java serialization kryo


【解决方案1】:

根据文档,可以通过多种方式解决此问题:

特定类型的序列化程序使用 Java 代码创建新实例 那种类型的。诸如 FieldSerializer 之类的序列化器是通用的,必须 处理创建任何类的新实例。默认情况下,如果一个类 有一个零参数构造函数,然后通过 ReflectASM 或 反射,否则抛出异常。如果零参数 构造函数是私有的,尝试通过反射访问它 使用 setAccessible。如果这是可以接受的,私人零参数 构造函数是允许 Kryo 创建类实例的好方法 不影响公共 API。

ReflectASM或反射无法使用时,可以配置Kryo 使用 InstantiatorStrategy 来处理创建 班级。 Objenesis 提供了使用 JVM 的 StdInstantiatorStrategy 无需调用任何 API 即可创建类实例的特定 API 构造函数。虽然这适用于许多 JVM,但零参数是 通常更便携。

kryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); Note that classes must be designed to be created in this way. If a class

期望其构造函数被调用,它可能处于未初始化状态 通过这种机制创建时的状态。

在许多情况下,您可能需要一个策略,其中 Kryo 优先 尝试查找并使用无参数构造函数,如果没有这样做, 它应该尝试使用 StdInstantiatorStrategy 作为后备,因为 这个根本不调用任何构造函数。配置为 这种行为可以这样表达:

kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));但是,默认行为是 需要一个无参数的构造函数。

Objenesis 还可以使用 Java 的内置函数创建新对象 序列化机制。使用这个,类必须实现 java.io.Serializable 和第一个零参数构造函数 超类被调用。

kryo.setInstantiatorStrategy(new SerializingInstantiatorStrategy()); You may also write your own

InstantiatorStrategy。

要仅自定义特定类型的创建方式, 可以设置 ObjectInstantiator。这将覆盖 ReflectASM, 反射和 InstantiatorStrategy。

Registration registration = kryo.register(SomeClass.class);
registration.setObjectInstantiator(...); Alternatively, some serializers provide methods that can be overridden to customize object

创造。

kryo.register(SomeClass.class, new FieldSerializer(kryo, SomeClass.class) {
   public Object create (Kryo kryo, Input input, Class type) {
      return new SomeClass("some constructor arguments", 1234);
   }
});

例子:

/**
 * Because the creation/initialization of Kryo instances is rather expensive, 
 * in a multithreaded scenario you should pool Kryo instances. A very simple solution 
 * is to bind Kryo instances to Threads using ThreadLocal, like this:
 */
private static final ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
    @Override
    protected Kryo initialValue() {
        Kryo kryo = new Kryo();
        /*
         * In many situations, you may want to have a strategy, where Kryo first tries to find and use a no-arg constructor 
         * and if it fails to do so, it should try to use StdInstantiatorStrategy as a fallback, because this one does 
         * not invoke any constructor at all. The configuration for this behavior could be expressed like this:
         */
        kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
        return kryo;
    }
};

【讨论】:

    猜你喜欢
    • 2011-12-14
    • 1970-01-01
    • 2015-12-09
    • 2020-05-09
    • 1970-01-01
    • 2017-04-21
    • 2017-12-27
    • 2019-10-11
    • 1970-01-01
    相关资源
    最近更新 更多