Акка удаленное развертывание недоразумение? - PullRequest
1 голос
/ 06 марта 2012

Я изучаю Akka (2.0-M4) и пытаюсь понять концепцию удаленного развертывания / создания субъекта .

Я предполагал, что удаленное развертывание работает, посылая код актера по сети, а затем запустив его, скажем, в микроядре. Это правильно?

Я спрашиваю, потому что не могу заставить это сделать. Если я скачаю примеры здесь , тогда актер CreationApp работает, но только если соответствующий jar-файл помещен в каталог lib микроядра. В противном случае я получаю ClassNotFoundException.

Я неправильно понял создание удаленного актера?

Ответы [ 2 ]

10 голосов
/ 06 марта 2012

Я думаю, вы неправильно поняли. Удаленное развертывание перенаправляет create на удаленный компьютер, но созданный Actor находится в системе ActorSystem на вашем локальном компьютере (для всех намерений и целей). Если код отсутствует на удаленном компьютере, вам не повезло.

4 голосов
/ 10 февраля 2014

В отличие от RMI не имеет встроенного механизма для отправки кода класса удаленная машина. Но Акка делает это очень легко сделать самостоятельно.

ActorSystem может быть создан с загрузчиком классов, который может загружать необходимые классы:

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

Ваш загрузчик классов может сотрудничать с актером, который принимает отправленные ему классы:

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)
  }
}

Этот актер хранит классы на карте, загрузчик классов получает классы с карты:

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
  }
}

и отправьте его RegistryActor на удаленной стороне в RegisterRemoteMsg

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