Akka远程部署误会?

时间:2012-03-05 20:38:06

标签: scala akka

我正在学习Akka(2.0-M4)并尝试理解remote actor deployment/creation的概念。

我假设远程部署通过在网络上发送actor代码然后在微内核上运行它来工作。这是对的吗?

我问,因为我无法做到这一点。如果我下载样本here,则actor CreationApp可以正常工作,但前提是相应的jar放在微内核的lib目录中。否则我得到一个ClassNotFoundException。

我是否误解了远程演员的创作?

2 个答案:

答案 0 :(得分:10)

我觉得你误解了。远程部署将 create 转发到远程计算机,但创建的Actor位于本地计算机上的ActorSystem内(出于所有意图和目的)。如果代码不在远程计算机上,那么你运气不好。

答案 1 :(得分:4)

与RMI相比,没有内置机制来发送类代码 一台远程机器。但是Akka让你自己很容易做到这一点。

可以使用可以加载必要类的类加载器创建ActorSystem:

val system = ActorSystem(
                 "TestSystem", 
                 ConfigFactory.load(), 
                 new ByteClassloader(
                       Thread.currentThread().getContextClassLoader()))

您的类加载器可以与接受发送给它的类的actor合作:

import akka.actor.Actor

// messages with classcode
case class RegisterRemoteMsg(name: String, clazzB: Array[Byte])

class RegistryActor extends Actor {
  def receive = {
    case RegisterRemoteMsg(name, bytes) =>
      ByteClassLoader.register(name, bytes)
  }
}

此actor将类存储在地图中,类加载器从地图中检索类:

import java.net.URLClassLoader
import java.net.URL

class ByteArrayClassloader(parent: ClassLoader) extends URLClassLoader(Array[URL](), parent) {
  import ByteClassLoader._
  override
  protected def findClass(name: String) : Class[_] = {
    var result = findLoadedClass(name);
    if (result == null) {
      try {
          result = findSystemClass(name);
      } catch {
          case e: /* ignore */ 
      }
    }
    if (result == null) {
      try {
          val classBytes = registeredClasses(name)
          result = defineClass(name, classBytes, 0, classBytes.length);
      } catch {
          case e: Exception => {
            throw new ClassNotFoundException(name);
          }
      }
    }
    result;
  }    
}
object ByteClassLoader {
  var registeredClasses : Map[String, Array[Byte]] = Map()
  def register(name : String, classBytes : Array[Byte]) {
    registeredClasses += (name -> classBytes)
  }
}

请注意,发送方必须发送字节代码 - 而不是类对象。 类对象(classOf [SomeClass])不可序列化,因为 它们“链接到”发送JVM。

类代码在磁盘上。请注意,scala类通常有一些嵌套 在单独的文件中的类。发件人可以找到所有必要的类 使用:

object LoadClassBytes {
  def apply(clazz: Class[_]) : Map[String, Array[Byte]] = { 
    val basePath : Path = Paths.get(clazz.getProtectionDomain.getCodeSource.getLocation.toURI)
    val relName = clazz.getName().replace('.', '/')
    val fullPath = basePath.resolve(relName)
    val fileName = fullPath.getFileName()
    val fileNameHead = (fileName.toString()).split("\\.")(0)
    val parentDir = fullPath.getParent()

    var res : Map[String, Array[Byte]] = Map()
    // find class file and class files of inner classes
    val ds = Files.newDirectoryStream(
        parentDir, 
        new DirectoryStream.Filter[Path]{
          def accept(file: Path) : Boolean = file.getFileName().toString().matches(fileNameHead+"(\\$.+)?\\.class")
        })
    try {
        val iter = ds.iterator()
        while (iter.hasNext()) {
          val p = iter.next()
          res += (((basePath.relativize(p)).toString().split("\\.")(0).replace('/', '.')) -> Files.readAllBytes(p))
        }
    } finally {
       ds.close
    }
    res
  }
}

并将其发送到RegisterRemoteMsg

中远程端的RegistryActor
 val registryActorR = ... retrieve remote registry actor ...
 val classesToBeSent = LoadClassBytes(classOf[SomeClass])
 for ((name, bytes) <- classesToBeSent) {
  registryActorR ! RegisterRemoteMsg(name, bytes)
 }