2011-08-31 26 views
10

我是新來Scala和阿卡所以請原諒我,如果這是對於新手的問題,但我找不到答案其他地方...爲什麼Scala無法實例化Companion對象?

對於我使用Scala的2.9.0-1和阿卡記錄1.1.3,幷包含了我的SBT 0.10.1設置。

我已經寫下了這封郵件的代碼,作爲Akka的實驗;它是用戶數據庫和註冊設施的玩具版本。基本思想是有一個UserPool Actor ActorPool,每個ActorPool都有一個MemoryUserDatabase的實例,它使用STM與用戶的電子郵件地址關聯的用戶圖進行交互 - 非常簡單,對吧?

該問題可以通過編譯文件並運行在兩個單獨的控制檯以下再現:

控制檯#1:

進口toy.service.user._; ServiceRunner.run

控制檯#2:

進口toy.service.user._; ClientRunner.run

這是從服務器控制檯輸出(#1)

Aug 31, 2011 5:21:29 PM org.multiverse.api.GlobalStmInstance <clinit> 
INFO: Initializing GlobalStmInstance using factoryMethod 'org.multiverse.stms.alpha.AlphaStm.createFast'. 
Aug 31, 2011 5:21:29 PM org.multiverse.stms.alpha.AlphaStm <init> 
INFO: Created a new AlphaStm instance 
Aug 31, 2011 5:21:29 PM org.multiverse.api.GlobalStmInstance <clinit> 
INFO: Successfully initialized GlobalStmInstance using factoryMethod 'org.multiverse.stms.alpha.AlphaStm.createFast'. 
[ERROR] [8/31/11 5:21 PM] [akka:event-driven:dispatcher:global-3] [LocalActorRef] Availability(foo) 
java.lang.NoClassDefFoundError: Could not initialize class toy.service.user.memory.MemoryUserDatabase$ 
    at toy.service.user.memory.MemoryUserDatabase$$anonfun$getUser$1.apply(Registration.scala:96) 
    at toy.service.user.memory.MemoryUserDatabase$$anonfun$getUser$1.apply(Registration.scala:96) 
    at toy.service.user.memory.MemoryUserDatabase$$anonfun$getUser$2.apply(Registration.scala:96) 
    at toy.service.user.memory.MemoryUserDatabase$$anonfun$getUser$2.apply(Registration.scala:96) 
    at akka.stm.Stm$$anon$1.call(Stm.scala:51) 
    at org.multiverse.templates.TransactionBoilerplate.executeWithTransaction(TransactionBoilerplate.java:279) 
    at org.multiverse.templates.TransactionBoilerplate.executeChecked(TransactionBoilerplate.java:218) 
    at org.multiverse.templates.TransactionBoilerplate.execute(TransactionBoilerplate.java:169) 
    at akka.stm.Stm$class.atomic(Stm.scala:50) 
    at akka.stm.package$.atomic(package.scala:10) 
    at akka.stm.Stm$class.atomic(Stm.scala:47) 
    at akka.stm.package$.atomic(package.scala:10) 
    at toy.service.user.memory.MemoryUserDatabase.getUser(Registration.scala:95) 
    at toy.service.user.UserDatabase$class.available(Registration.scala:88) 
    at toy.service.user.memory.MemoryUserDatabase.available(Registration.scala:92) 
    at toy.service.user.UserServer$$anonfun$receive$1.apply(Registration.scala:77) 
    at toy.service.user.UserServer$$anonfun$receive$1.apply(Registration.scala:76) 
    at akka.actor.Actor$class.apply(Actor.scala:478) 
    at toy.service.user.UserServer.apply(Registration.scala:74) 
    at akka.actor.LocalActorRef.invoke(ActorRef.scala:860) 
    at akka.dispatch.MessageInvocation.invoke(MessageHandling.scala:26) 
    at akka.dispatch.ExecutableMailbox$class.processMailbox(ExecutorBasedEventDrivenDispatcher.scala:214) 
    at akka.dispatch.ExecutorBasedEventDrivenDispatcher$$anon$4.processMailbox(ExecutorBasedEventDrivenDispatcher.scala:120) 
    at akka.dispatch.ExecutableMailbox$class.run(ExecutorBasedEventDrivenDispatcher.scala:186) 
    at akka.dispatch.ExecutorBasedEventDrivenDispatcher$$anon$4.run(ExecutorBasedEventDrivenDispatcher.scala:120) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
    at java.lang.Thread.run(Thread.java:680) 
    at akka.dispatch.MonitorableThread.run(ThreadPoolBuilder.scala:181) 

錯誤是使用稍微更有趣的Scala 2.9.1.final:

Aug 31, 2011 5:38:35 PM org.multiverse.api.GlobalStmInstance <clinit> 
INFO: Initializing GlobalStmInstance using factoryMethod 'org.multiverse.stms.alpha.AlphaStm.createFast'. 
Aug 31, 2011 5:38:35 PM org.multiverse.api.GlobalStmInstance getMethod 
INFO: Failed to initialize GlobalStmInstance through System property 'org.multiverse.api.GlobalStmInstance.factoryMethod' with value 'org.multiverse.stms.alpha.AlphaStm'.'org.multiverse.stms.alpha.AlphaStm.createFast' is not an existing class (it can't be found using the Thread.currentThread.getContextClassLoader). 
[ERROR] [8/31/11 5:38 PM] [akka:event-driven:dispatcher:global-3] [LocalActorRef] Availability(foo) 
java.lang.ExceptionInInitializerError 
    at akka.stm.TransactionFactory.<init>(TransactionFactory.scala:172) 
    at akka.stm.TransactionFactory$.apply(TransactionFactory.scala:122) 
    at akka.stm.Stm$class.$init$(Stm.scala:44) 
    at akka.stm.package$.<init>(package.scala:10) 
    at akka.stm.package$.<clinit>(package.scala) 
    at toy.service.user.memory.MemoryUserDatabase.getUser(Registration.scala:95) 
    at toy.service.user.UserDatabase$class.available(Registration.scala:88) 
    at toy.service.user.memory.MemoryUserDatabase.available(Registration.scala:92) 
    at toy.service.user.UserServer$$anonfun$receive$1.apply(Registration.scala:77) 
    at toy.service.user.UserServer$$anonfun$receive$1.apply(Registration.scala:76) 
    at akka.actor.Actor$class.apply(Actor.scala:478) 
    at toy.service.user.UserServer.apply(Registration.scala:74) 
    at akka.actor.LocalActorRef.invoke(ActorRef.scala:860) 
    at akka.dispatch.MessageInvocation.invoke(MessageHandling.scala:26) 
    at akka.dispatch.ExecutableMailbox$class.processMailbox(ExecutorBasedEventDrivenDispatcher.scala:214) 
    at akka.dispatch.ExecutorBasedEventDrivenDispatcher$$anon$4.processMailbox(ExecutorBasedEventDrivenDispatcher.scala:120) 
    at akka.dispatch.ExecutableMailbox$class.run(ExecutorBasedEventDrivenDispatcher.scala:186) 
    at akka.dispatch.ExecutorBasedEventDrivenDispatcher$$anon$4.run(ExecutorBasedEventDrivenDispatcher.scala:120) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
    at java.lang.Thread.run(Thread.java:680) 
    at akka.dispatch.MonitorableThread.run(ThreadPoolBuilder.scala:181) 
Caused by: java.lang.IllegalArgumentException: Failed to initialize GlobalStmInstance through System property 'org.multiverse.api.GlobalStmInstance.factoryMethod' with value 'org.multiverse.stms.alpha.AlphaStm'.'org.multiverse.stms.alpha.AlphaStm.createFast' is not an existing class (it can't be found using the Thread.currentThread.getContextClassLoader). 
    at org.multiverse.api.GlobalStmInstance.getMethod(GlobalStmInstance.java:82) 
    at org.multiverse.api.GlobalStmInstance.<clinit>(GlobalStmInstance.java:38) 
    ... 22 more 
Caused by: java.lang.ClassNotFoundException: org.multiverse.stms.alpha.AlphaStm 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247) 
    at org.multiverse.api.GlobalStmInstance.getMethod(GlobalStmInstance.java:76) 
    ... 23 more 

該執行部分的代碼是:

class MemoryUserDatabase extends UserDatabase { 
    import MemoryUserDatabase._ 

    def getUser(email: String) = atomic { 
    users.get.get(email) 
    } 
    def register(user: User) = atomic { 
    getUser(user.email) match { 
     case None => 
     users alter (_ + (user.email -> user)) 
     true 
     case Some(found) => false 
    } 
    } 
} 
object MemoryUserDatabase { 
    import scala.collection.mutable.{ Map => MutMap } 
    private val users = Ref(MutMap[String, User]()) 
} 

我不明白爲什麼Companion對象無法初始化。最奇怪的是,你可以做同樣的事情,但如果在服務器控制檯(#1)你第一次訪問協同對象:

運行ServerRunner之前它只是初始化

MemoryUserDatabase罰款,隨後一切都只是花花公子。

任何人都可以解釋爲什麼這是?

謝謝! Idan

PS。這是我的第一個Scala代碼,所以儘量不要太難以發笑......並且歡迎任何其他建議(風格,哲學,神學......)。

package toy.service.user 

import scala.collection.mutable.HashMap 

import akka.actor.{ Actor, ActorRef } 
import akka.config.Supervision.{ OneForOneStrategy, Permanent } 
import Actor._ 
import akka.routing._ 
import akka.stm._ 
import akka.actor.TypedActor 
import akka.event.EventHandler 

class User(var email: String, 
      var password: String) extends Serializable 

/** Registration message types. 
*/ 
sealed trait RegistrationMessage 
case class Availability(email: String) extends RegistrationMessage 
case class GetUser(email: String) extends RegistrationMessage 
case class Register(user: User) extends RegistrationMessage 

// Client --------------------------------------- 
class UserClient(defaultTimeout: Int = 1000) { 
    val userService = Actor.remote.actorFor(UserService.USER_SERVICE_ID, "localhost", UserService.USER_SERVICE_PORT) 
    EventHandler.info(this, "remote UserService: id(" + userService.id + "), uuid(" + userService.uuid + ")") 

    def getUser(email: String, timeout: Int = defaultTimeout): Option[User] = (userService !! (GetUser(email), timeout)).as[User] 

    def available(email: String, timeout: Int = defaultTimeout): Boolean = 
    (userService !! (Availability(email), timeout)).as[Boolean].getOrElse(throw new RuntimeException("Oi!")) 

    def register(user: User, timeout: Int = defaultTimeout): Boolean = 
    (userService !! (Register(user), timeout)).as[Boolean].getOrElse(throw new RuntimeException("Got bogus (None) response from " + UserService.USER_SERVICE_ID)) 
} 

// Service Pool --------------------------------- 
object UserService { 
    val USER_SERVICE_ID = "user:service" 
    val USER_SERVICE_PORT = 2662 
    val host = "localhost" 
} 

class UserService extends Actor 
    with DefaultActorPool 
    with BoundedCapacityStrategy 
    with MailboxPressureCapacitor 
    with SmallestMailboxSelector 
    with BasicFilter { 

    import toy.service.user.memory._ 

    def receive = _route // DefaultActorPool's receive 
    def lowerBound = 1 
    def upperBound = 5 
    def pressureThreshold = 1 
    def partialFill = true // never send duplicate messages to same actor (only meaningful if selectionCount > 1) 
    def selectionCount = 1 // How many in pool should receive each message 
    def rampupRate = 0.1 // increase by 10% capacity (# num actors) 
    def backoffRate = 0.50 // halve capacity once backoffThreshold is reached 
    def backoffThreshold = 0.50 
    def instance = actorOf(new UserServer(new MemoryUserDatabase)) 

    override def preStart() { 
    import UserService.{ host, USER_SERVICE_ID, USER_SERVICE_PORT } 

    remote.start(host, UserService.USER_SERVICE_PORT); 
    remote.register(UserService.USER_SERVICE_ID, self) //Register the actorPool with the specified service id 
    EventHandler.info(this, "Prestart: Started UserService(" + self.uuid + ") on %s:%s".format(host, UserService.USER_SERVICE_PORT.toString())) 
    } 
} 

// Service -------------------------------------- 
class UserServer(db: UserDatabase) extends Actor { 

    def receive = { 
    case Availability(email) => self.reply(db.available(email)) 
    case GetUser(email)  => self.reply(db.getUser(email)) 
    case Register(user)  => self.reply(db.register(user)) 
    } 
} 

// Database ------------------------------------- 
trait UserDatabase { 
    def getUser(email: String): Option[User] 
    def register(user: User): Boolean 

    def available(email: String): Boolean = getUser(email) == None 
} 

package memory { 
    class MemoryUserDatabase extends UserDatabase { 
    import MemoryUserDatabase._ 

    def getUser(email: String) = atomic { 
     users.get.get(email) 
    } 

    def register(user: User) = atomic { 
     getUser(user.email) match { 
     case None => 
      users alter (_ + (user.email -> user)) 
      true 
     case Some(found) => false 
     } 
    } 
    } 

    object MemoryUserDatabase { 
    import scala.collection.mutable.{ Map => MutMap } 

    private val users = Ref(MutMap[String, User]()) 
    } 
} 

object ServerRunner { 
    def run() { 
    actorOf[UserService].start() 
    } 
} 

object ClientRunner { 
    def run { 
    val client = new UserClient 
    EventHandler.info(this, client.available("foo")) 
    } 
} 
+0

最近發佈了Scala 2.9.1。也許在那裏拍一下? –

+0

我認爲你需要添加更多的堆棧跟蹤以供任何使用。 –

+2

另外,你正在使用共享的,unthreadsafe狀態,這是一個很大的禁止 –

回答

1

我在我的應用程序啓動過程中創建的對象的構造函數中初始化TMap時遇到了類似的問題。不知何故,我的對象是在STM靜態初始化器運行之前創建的。我讓我的對象的領域很懶,並且解決了這個問題。

...實際上它只是將問題推遲到程序的後面。 GRRRR。

+0

你的方法工作正常。在添加懶惰修飾符後,問題似乎解決了。 –

0

我遇到了同樣的問題。添加依賴'org.multiverse.multiverse-alpha-unborn'解決了我的問題。

相關問題