【问题标题】:Transferring object messages between Java app and Scala app via Akka通过 Akka 在 Java 应用程序和 Scala 应用程序之间传输对象消息
【发布时间】:2013-10-31 10:02:13
【问题描述】:

我有两个项目。第一个是用 Java 编写并使用 Akka,而第二个是 Scala 项目,它也使用了 Akka actor。在发送公共对象和字段(即String)方面,我已经在两者之间建立了成功的连接。我想要的是能够在两者之间发送自定义Objects,例如User。因此,Java 端将仅具有实体,而 Scala 端将分别具有Case classes

Java:

1.User.java:

public class User implements Serializable {
  public final String name;
  public User(String name) {
    this.name = name;
  }
  @Override
  public String toString() {
    return "User [name=" + name + "]";
  }
}

2.Hello App 类:

public class Boot {
  public static void main(String[] args) {
    ActorSystem system;
    ActorSelection remoteActor;

    Config config = ConfigFactory.load().getConfig("hello");
    system = ActorSystem.create("HelloApplication");

    String remoteAcPath = config.getString("remote-user-actor");
    remoteUserHandleActor = system.actorSelection(remoteAcPath);

    User u = new User("Alex");

    System.out.println("Sending message to Remote Actor ...");
    remoteUserHandleActor.tell(u, userActor);
  }
}

斯卡拉

1.用户案例类:

case class User(val name: String) extends Serializable

2.你好应用:

object Boot extends App {

  implicit val ec = ExecutionContext
  implicit val timeout = Timeout(5 seconds)

  lazy implicit val config: Config = ConfigFactory.load
  val system = ActorSystem("HelloServer")
  val userActor = system.actorOf(Props[UserHandleActor], name = "userHandlerActor")
}

向 Scala Actor 发送带有 Java Actor 的消息会导致 Java 端出现 dead letters 错误:

[HelloApplication-akka.actor.default-dispatcher-15] INFO  akka.actor.LocalActorRef - Message [akka.remote.transport.AssociationHandle$Disassociated] from Actor[akka://HelloApplication/deadLetters] to Actor[akka://HelloApplication/system/transports/akkaprotocolmanager.tcp0/akkaProtocol-tcp%3A%2F%2FHelloServer%40127.0.0.1%3A1111-1#-1775289115] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
[HelloApplication-akka.actor.default-dispatcher-5] INFO  akka.actor.LocalActorRef - Message [akka.remote.transport.ActorTransportAdapter$DisassociateUnderlying] from Actor[akka://HelloApplication/deadLetters] to Actor[akka://HelloApplication/system/transports/akkaprotocolmanager.tcp0/akkaProtocol-tcp%3A%2F%2FHelloServer%40127.0.0.1%3A1111-1#-1775289115] was not delivered. [2] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

Scala 端显示此消息:

31/10/2013 09:04:38 UTC | DEBUG | Remoting HelloServer-akka.actor.default-dispatcher-3 - Associated [akka.tcp://HelloServer@127.0.0.1:1111] <- [akka.tcp://HelloApplication@192.162.1.4:2552]
31/10/2013 09:04:38 UTC | DEBUG | akka.remote.EndpointWriter HelloServer-akka.actor.default-dispatcher-3 - Disassociated [akka.tcp://HelloServer@127.0.0.1:1111] <- [akka.tcp://HelloApplication@192.162.1.4:2552]
31/10/2013 09:04:38 UTC | INFO  | akka.actor.LocalActorRef HelloServer-akka.actor.default-dispatcher-5 - Message [akka.remote.transport.AssociationHandle$Disassociated] from Actor[akka://HelloServer/deadLetters] to Actor[akka://HelloServer/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FHelloApplication%40192.162.1.4%3A2552-0/endpointWriter/endpointReader-akka.tcp%3A%2F%2FHelloApplication%40192.162.1.4%3A2552-0#526150656] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
31/10/2013 09:04:38 UTC | INFO  | akka.actor.LocalActorRef HelloServer-akka.actor.default-dispatcher-5 - Message [akka.remote.transport.AssociationHandle$Disassociated] from Actor[akka://HelloServer/deadLetters] to Actor[akka://HelloServer/system/transports/akkaprotocolmanager.tcp0/akkaProtocol-tcp%3A%2F%2FHelloServer%40127.0.0.1%3A54194-1#-802595184] was not delivered. [2] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
31/10/2013 09:04:38 UTC | DEBUG | akka.remote.EndpointWriter HelloServer-akka.actor.default-dispatcher-6 - Associated [akka.tcp://HelloServer@127.0.0.1:1111] -> [akka.tcp://HelloApplication@192.162.1.4:2552]
31/10/2013 09:04:38 UTC | DEBUG | Remoting HelloServer-akka.actor.default-dispatcher-3 - Associated [akka.tcp://HelloServer@127.0.0.1:1111] <- [akka.tcp://HelloApplication@192.162.1.4:2552]

之后,我想出了一个疯狂的想法,我将相同的serialVersionUID(即serialVersionUID = 888L)设置为 User.java 实体和 User case 类,有趣的是,消息处理成功,一切都很好。我知道此时我在序列化方面做错了。

1) 实现我的目标的最佳选择是什么?

2) 如果有在 Java 和 Scala 之间转换自定义对象的方法(我知道 javaconversions 用于集合等),那就太好了。

编辑

3) 我的疯狂的想法在两边设置相同的serialVersionUID 正确吗?

【问题讨论】:

  • 我会在一个共享的 java 项目中引入 DTO,你的 scala 和 java 应用程序都应该使用它们来传输数据。
  • @mr.boyfox 对,我也不想在 scala 项目中使用 java 类。那不是另一种方式吗? ——
  • 我在这里看不到任何其他“架构上干净”的选择。还要考虑重构和可维护性。什么可以保证您的 java 和 scala 类始终保持同步?
  • 很多人说写自己的序列化器类(并使用google protobuf),但这是否正确
  • 编写自己的序列化程序并使用 protobuf 或类似方法是一种可能的解决方案。如前所述,共享 Java 类是另一种解决方案。

标签: java scala akka


【解决方案1】:

一种选择是在两个项目中都使用 Java 类,并在它们之上提供一些层,以便它们可以在 Scala 中使用,就像它们是案例类一样。

例如,假设你只有一个 Java 版本的 User 类,你可以在 Scala 端这样做:

object User {
  // will allow you to create User instances without the 'new' keyword
  def apply(name: String) = 
    new User(name)

  // will allow you to pattern-match against User instances, for example in
  // actor's 'receive' function
  def unapply(user: User) = 
    Some(user.name)

  // implicit wrapper that will add some Scala-like API to your User class
  implicit class UserScalaApi(user: User) {
    // whatever you need here (the 'copy' method, etc.)
  }
}

这样做的缺点是你必须为每个 Java 类创建这样的适配层(宏注解在这里会很棒......)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 2010-11-06
    • 2011-03-11
    • 1970-01-01
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多