跳到主要内容
版本:0.11

Scala 序列化

Apache Fory™ 支持所有 Scala 对象的序列化:

  • 支持 case class 序列化
  • 支持 pojo/bean class 序列化
  • 支持 object 单例对象序列化
  • 支持 collection 集合序列化
  • 其他类型如 tuple/either 以及基础类型也都支持

同时支持 Scala 2 和 Scala 3。

安装

如果你使用 sbt 并希望在 Scala 2 项目中引入 Fory Scala 依赖,请添加如下内容:

libraryDependencies += "org.apache.fory" % "fory-scala_2.13" % "0.11.2"

如果你使用 sbt 并希望在 Scala 3 项目中引入 Fory Scala 依赖,请添加如下内容:

libraryDependencies += "org.apache.fory" % "fory-scala_3" % "0.11.2"

快速开始

case class Person(name: String, id: Long, github: String)
case class Point(x : Int, y : Int, z : Int)

object ScalaExample {
val fory: Fory = Fory.builder().withScalaOptimizationEnabled(true).build()
// 注册针对 Scala 优化的 fory 序列化器
ScalaSerializers.registerSerializers(fory)
fory.register(classOf[Person])
fory.register(classOf[Point])

def main(args: Array[String]): Unit = {
val p = Person("Shawn Yang", 1, "https://github.com/chaokunyang")
println(fory.deserialize(fory.serialize(p)))
println(fory.deserialize(fory.serialize(Point(1, 2, 3))))
}
}

Fory 实例创建

在使用 fory 进行 Scala 序列化时,建议至少以如下方式创建 fory 实例:

import org.apache.fory.Fory
import org.apache.fory.serializer.scala.ScalaSerializers

val fory = Fory.builder().withScalaOptimizationEnabled(true).build()

// 注册针对 Scala 优化的 fory 序列化器
ScalaSerializers.registerSerializers(fory)

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

fory.register(Class.forName("scala.Enumeration.Val"))

如果你希望避免手动注册这些类型,可以通过 ForyBuilder#requireClassRegistration(false) 关闭类注册功能。 注意:关闭类注册后,可以反序列化未知类型的对象,灵活性更高,但如果反序列化的类包含恶意代码,可能存在安全风险。

Scala 中循环引用较为常见,建议通过 ForyBuilder#withRefTracking(true) 启用引用跟踪(Reference tracking)。如果未启用引用跟踪,在某些 Scala 版本下序列化 Scala Enumeration 时,可能会出现 StackOverflowError

注意:fory 实例应在多次序列化操作间复用,fory 实例的创建开销较大。

如果你需要在多线程环境下共享 fory 实例,应通过 ForyBuilder#buildThreadSafeFory() 创建 ThreadSafeFory 实例。

序列化 case class

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

序列化 pojo

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

序列化 object 单例对象

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

序列化集合(Collection)

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

序列化 Tuple

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

序列化 Enum

Scala3 Enum

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

Scala2 Enum

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

序列化 Option

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

性能

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

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

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

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

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