跳到主要内容

Scala 序列化指南

Apache Fury 支持所有 Scala 对象序列化:

  • case 支持类序列化;
  • pojo/bean 支持类序列化;
  • object 支持单例序列化;
  • collection 支持序列化;
  • 其他类型(如 tuple/either AND BASIC 类型)也都受支持。

Scala 2 和 3 均支持。

安装

libraryDependencies += "org.apache.fury" % "fury-core" % "0.7.1"

Fury 对象创建

当使用 Apache Fury 进行 Scala 序列化时,您应该至少使用以下选项创建 Fury 对象:

val fury = Fury.builder()
.withScalaOptimizationEnabled(true)
.requireClassRegistration(true)
.withRefTracking(true)
.build()

根据您序列化的对象类型,您可能需要注册一些 Scala 的内部类型:

fury.register(Class.forName("scala.collection.generic.DefaultSerializationProxy"))
fury.register(Class.forName("scala.Enumeration.Val"))

如果要避免此类注册,可以通过禁用类 FuryBuilder#requireClassRegistration(false) 来完成。

请注意:此选项可以反序列化未知的对象类型,使用更灵活。但如果类包含任何的恶意代码,会有安全风险。

循环引用在 Scala 中很常见,Reference tracking 应该由 FuryBuilder#withRefTracking(true) 配置选项开启。如果不启用 Reference tracking,则在序列化 Scala Enumeration 时,某些 Scala 版本可能会发生 StackOverflowError 错误

注意:Fury 实例应该在多个序列化之间共享,创建 Fury 实例开销很大,应该尽量复用。

如果您在多个线程中使用共享的 Fury 实例,您应该使用 ThreadSafeFury 代替 FuryBuilder#buildThreadSafeFury()

序列化 case 对象

case class Person(github: String, age: Int, id: Long)
val p = Person("https://github.com/chaokunyang", 18, 1)
println(fury.deserialize(fury.serialize(p)))
println(fury.deserializeJavaObject(fury.serializeJavaObject(p)))

序列化 pojo

class Foo(f1: Int, f2: String) {
override def toString: String = s"Foo($f1, $f2)"
}
println(fury.deserialize(fury.serialize(Foo(1, "chaokunyang"))))

序列化对象单例

object singleton {
}
val o1 = fury.deserialize(fury.serialize(singleton))
val o2 = fury.deserialize(fury.serialize(singleton))
println(o1 == o2)

序列化集合

val seq = Seq(1,2)
val list = List("a", "b")
val map = Map("a" -> 1, "b" -> 2)
println(fury.deserialize(fury.serialize(seq)))
println(fury.deserialize(fury.serialize(list)))
println(fury.deserialize(fury.serialize(map)))

序列化元组

val tuple = Tuple2(100, 10000L)
println(fury.deserialize(fury.serialize(tuple)))
val tuple = Tuple4(100, 10000L, 10000L, "str")
println(fury.deserialize(fury.serialize(tuple)))

序列化枚举

Scala3 枚举

enum Color { case Red, Green, Blue }
println(fury.deserialize(fury.serialize(Color.Green)))

Scala2 枚举

object ColorEnum extends Enumeration {
type ColorEnum = Value
val Red, Green, Blue = Value
}
println(fury.deserialize(fury.serialize(ColorEnum.Green)))

序列化 Option 类型

val opt: Option[Long] = Some(100)
println(fury.deserialize(fury.serialize(opt)))
val opt1: Option[Long] = None
println(fury.deserialize(fury.serialize(opt1)))

性能

pojo/bean/case/object Scala 对 Apache Fury JIT 的支持很好,性能与 Apache Fury Java 一样优异。

Scala 集合和泛型不遵循 Java 集合框架,并且未与当前发行版中的 Apache Fury JIT 完全集成。性能不会像 Java 的 Fury collections 序列化那么好。

scala 集合的执行将调用 Java 序列化 API writeObject/readObject/writeReplace/readResolve/readObjectNoData/Externalizable 和 Fury ObjectStream 实现。虽然 org.apache.fury.serializer.ObjectStreamSerializer 比 JDK ObjectOutputStream/ObjectInputStream 快很多,但它仍然不知道如何使用 Scala 集合泛型。

未来我们计划为 Scala 类型提供更多优化,敬请期待,更多信息请参看 #682

Scala 集合序列化已在 #1073 完成 ,如果您想获得更好的性能,请使用 Apache Fury snapshot 版本。