2012-03-05 4 views
1

Я изучаю Akka (2.0-M4) и пытаюсь понять концепцию remote actor deployment/creation.Akka удаленное развертывание непонимание?

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

Прошу, потому что я не могу заставить это сделать это. Если я загружаю образцы here, то актер CreationApp работает, но только в том случае, если соответствующая банка помещается в каталог lib микроядра. В противном случае я получаю исключение ClassNotFoundException.

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

ответ

10

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

+0

Да, Акка не претендует сделать удаленный загрузку классов. –

+0

Другими словами, i STILL нужно скопировать по двоичным файлам на удаленную машину, PRIOR для развертывания актера, не так ли? – himekami

4

В отличие от 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) 
} 
+0

интересно, но довольно много проблем с безопасностью? Как аутентифицируется абонент? –

Смежные вопросы