Abh*_*kar 1 java serialization scala akka-persistence
我正在研究 akka 持久性并遇到了对象序列化的典型问题。我的对象(如下所示)具有基本类型和功能。我读了this,this和this,但没有人帮助我使以下可序列化。
测试工具
object SerializationUtil {
def write(obj: Any): String = {
val temp = Files.createTempFile(null, null).toFile
val out = new ObjectOutputStream(new FileOutputStream(temp))
out.writeObject(obj)
out.close()
temp.deleteOnExit()
temp.getAbsolutePath
}
def read[T](file: String) = {
val in = new ObjectInputStream(new FileInputStream(new File(file)))
val obj = in.readObject().asInstanceOf[T]
in.close()
obj
}
}
Run Code Online (Sandbox Code Playgroud)
统计数据
case class Stats(
app: String,
unit: ChronoUnit,
private var _startupDurations: List[Long]
) {
def startupDurations = _startupDurations.sorted
def startupDurations_=(durations: List[Long]) = _startupDurations = durations
@transient lazy val summary: LongSummaryStatistics = {
_startupDurations.asJava.stream()
.collect(summarizingLong(identity[Long]))
}
}
Run Code Online (Sandbox Code Playgroud)
Stats 序列化就好了。
"SerializationUtil" should "(de)serialize Stats" in {
val file = SerializationUtil.write(newStats())
val state = SerializationUtil.read[Stats](file)
verifyStats(state)
}
Run Code Online (Sandbox Code Playgroud)
但这不会: case class GetStatsForOneRequest(app: String, callback: Stats => Unit)
java.io.NotSerializableException: org.scalatest.Assertions$AssertionsHelper
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
Run Code Online (Sandbox Code Playgroud)
还试过:
trait SerializableRunnable[T] extends scala.Serializable with ((T) => Unit)
Run Code Online (Sandbox Code Playgroud)
将回调实现为 的实例SerializableRunnable,但没有运气。
想法?
编辑:
也许我应该澄清遇到此问题的实际用例以提供更多上下文。该函数是来自 Akka HTTP路由的回调,如下所示:
path("stats") {
logRequest("/stats") {
completeWith(instanceOf[List[Stats]]) { callback =>
requestHandler ! GetStatsRequest(callback)
}
}
}
Run Code Online (Sandbox Code Playgroud)
该处理器的演员坚持请求,直到得到响应。构建最终输出可能需要多个响应。
我做了一些挖掘,看来回调实现是CallbackRunnable。
也许你没有完全理解链接的文章。函数序列化的问题在于闭包中捕获的任何内容也必须是可序列化的。你需要的是孢子。一切都在那里解释,但这里是要点:
Scala 中的 Lambda 函数可以引用外部作用域中的变量,而无需将它们明确列为参数。执行此操作的函数称为闭包,并捕获它所引用的外部变量。例如foo在传递给map下面的闭包中捕获:
val foo = 42
List(1,2,3).map(_ + foo)
Run Code Online (Sandbox Code Playgroud)
看看上面的例子 wherefoo是一个原始值,你不会认为这是一个问题。但是当有一个封闭类时会发生什么?
class C {
val myDBconn = ...
val foo = 42
List(1,2,3).map(_ + foo)
}
Run Code Online (Sandbox Code Playgroud)
现在(出乎许多程序员的意料)闭包捕获了整个this不可序列化的封闭类,包括myDBconn,因为foo引用了 getter 方法this.foo。
解决方案是不在this闭包中捕获。例如,val为我们需要捕获的任何值创建一个 local使函数再次可序列化:
class C {
val myDBconn = ...
val foo = 42
{
val localFoo = foo
List(1,2,3).map(_ + localFoo)
}
}
Run Code Online (Sandbox Code Playgroud)
当然,手动执行此操作很乏味,因此Spores。
| 归档时间: |
|
| 查看次数: |
2170 次 |
| 最近记录: |