如何在自定义Serializer中获取Akka的JacksonJsonSerializer实例?
我想在序列化对象的manifest和JSON表示中添加一些额外信息,但不想处理akka.serialization.jackson.JacksonJsonSerializer已经完美覆盖的所有细节场景和迁移问题。因此,我希望在自定义Serializer中获取JacksonJsonSerializer的引用,以便轻松装饰输出而无需重新实现所有逻辑。
我尝试通过全限定名(FQN)获取该Serializer:
private lazy val jackson = { SerializationExtension(system) .serializerOf("akka.serialization.jackson.JacksonJsonSerializer") .map(_.asInstanceOf[SerializerWithStringManifest]) .get }
但抛出了异常:
java.lang.NoSuchMethodException: akka.serialization.jackson.JacksonJsonSerializer.
()
原因是JacksonJsonSerializer的构造方法需要ExtendedActorSystem和一个绑定名称字符串,而akka.serialization.Serialization#serializerOf方法在绑定名称为空时会重抛这个异常,我却无法传入绑定名称。
我的问题是:能否通过ExtendedSystem或akka.serialization.Serializer的其他可用方式获取已存在的Serializer实例?
方法1:通过配置绑定名称获取复用实例
Akka的序列化机制会根据配置中的绑定初始化Serializer实例,先在application.conf中为JacksonJsonSerializer配置绑定别名:
akka.actor.serialization-bindings { # 可选:绑定你需要序列化的类型到Jackson序列化器 "com.yourpackage.YourSerializableType" = jackson-json # 明确指定别名对应的序列化器类 jackson-json = "akka.serialization.jackson.JacksonJsonSerializer" }
然后在自定义Serializer中,通过绑定别名获取已初始化的实例:
import akka.serialization.SerializationExtension import akka.serialization.jackson.JacksonJsonSerializer import akka.actor.ExtendedActorSystem import akka.serialization.SerializerWithStringManifest class CustomDecoratorSerializer(system: ExtendedActorSystem) extends SerializerWithStringManifest { // 通过配置的绑定名称获取复用的Jackson序列化器实例 private lazy val jacksonSerializer: JacksonJsonSerializer = SerializationExtension(system) .serializerFor("jackson-json") .asInstanceOf[JacksonJsonSerializer] override def toBinary(o: AnyRef): Array[Byte] = { // 先让Jackson处理核心序列化 val originalBytes = jacksonSerializer.toBinary(o) // 在这里添加你的自定义逻辑,比如包装JSON、追加额外字段等 // ... originalBytes } override def manifest(o: AnyRef): String = { val originalManifest = jacksonSerializer.manifest(o) // 给manifest添加自定义标识,方便反序列化时识别 s"decorated_$originalManifest" } override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef = { // 先还原原始manifest,再交给Jackson反序列化 val originalManifest = manifest.replace("decorated_", "") jacksonSerializer.fromBinary(bytes, originalManifest) } }
方法2:直接构造实例(不推荐)
如果不想依赖配置,可以直接通过ExtendedActorSystem和绑定名称构造实例,但这会创建新实例,无法复用Akka全局配置的序列化器参数:
private lazy val jacksonSerializer: JacksonJsonSerializer = new JacksonJsonSerializer(system, "custom-jackson-binding")
方法3:从序列化注册表查找已初始化实例
如果JacksonJsonSerializer已经被Akka初始化过(比如有其他类型绑定到它),可以遍历序列化器注册表获取实例:
import akka.serialization.Serialization private lazy val jacksonSerializer: JacksonJsonSerializer = { val serialization = SerializationExtension(system).asInstanceOf[Serialization] serialization.serializers.values .collectFirst { case js: JacksonJsonSerializer => js } .getOrElse(throw new IllegalStateException("JacksonJsonSerializer not initialized in Akka")) }
这种方式无需额外配置,但依赖于Akka已经初始化过该序列化器,否则会抛出异常。
内容的提问来源于stack exchange,提问作者gervais.b

