2014-03-02 10 views
3

현재 Play2.2 응용 프로그램에서 Depalency Injection 용 Scaldi를 사용하고 있습니다.Scaldi 의존성 주입 및 Akka 액터

나는 Scaldi의 웹 사이트에있는 문서를 읽었지만 Akka와 함께 사용하는 방법이 무엇인지 분명하지 않습니다.

내가 내 프로젝트에 지금까지 가지고

class UserService extends ServiceActor with Injection 
{ 
    val userManager = inject[UserManager] 

    def receive = { 
     case Register(email: String, password: String) 
    } 
} 

object UserService extends Service 
{ 
    case class Register(email: String, password: String) 

    override protected val actorRef = Akka.system.actorOf(Props[UserService].withRouter(SmallestMailboxRouter(resizer = Some(resizer)))) 
} 

그런 다음 주입 관리자에 따라 : 나는이 작업을 수행 할 UserManager의 인스턴스를 사용하는 것이 UserService.scala에서

Models/ (Daos and case classes) 
    User.scala 
Services/ (Akka Actors) 
    UserService.scala 
    ProfileService.scala 
Managers/ (Regular Manager Classes) 
    UserManager.scala (The Trait Interface) 
    UserManagerImpl.scala (An actual implementation) 
    UserManagerMock.scala (Mocked version) 
    etc.. 

배우가 모든 작업을 관리자에게 위임하면 조롱받을 수 있습니다.

그러나 관리자가 동반자 개체 인 다른 서비스를 호출해야한다면 어떻게해야합니까? 또는 컴패니언 개체를 통해 참조되는 다른 서비스를 호출하는 서비스?

누군가가 Akka를 Scaldi와 통합하는 방법에 대한 지침이 있습니까?

답변

4

귀하는 동반자 인 object을 서비스로 사용하고 있다고 말씀하셨습니다. 나는 또한 당신이 object 안에 배우를 만드는 것을 발견했습니다. 일반적으로 나는 이것을하지 못하게 할 것입니다. 스칼라 (컴패니언) object s 은 단지 싱글 톤입니다. 어떤 상황에서는 유용하고 적절할 수 있지만 일반적으로 응용 프로그램에서 종속성 주입 또는 제어 반전을 수행하려는 경우 패턴이 아닌 패턴 반 패턴으로 간주됩니다 (일반적으로 ). 여기에는 많은 이유가 있지만,이 경우 가장 중요한 것은 모의하기가 어렵다는 것입니다. 인스턴스화를 제어하는 ​​것이 어렵고 일반적으로 제어 반전의 반대를 나타냅니다.

또 다른 문제점은 이러한 싱글 톤 개체 내부에 액터를 생성한다는 것입니다. 배우 모델의 매우 중요한 부분은 supervision hierarchy입니다. 이 액터를 작성하여 (귀하의 경우 UserService)을 작성하면 보호자가 감독자가되도록 할 수 있습니다. 대부분의 경우 은 원하는 것이 아닙니다. 따라서 최상위 액터가되어야하는 몇 명을 제외하고 다른 액터 내에서 대부분의 액터를 만드는 것이 좋습니다. 이것은 그들이 적절한 감독 계층을 가지고 있는지 확인합니다.

이러한 아이디어는 Scaldi를 사용하는 경우에도 마찬가지입니다. scaldi-akka은 에 특정 행위자에 대해 ActorRef 또는 Props을 삽입하는 편리한 방법을 제공합니다. injectActorRef 생성하고 현재 배우의 맥락에서 배우 것을

class ProfileManager (implicit inj: Injector) extends Injectable 

trait UserManager { 
    def register(email: String, password: String): User 
} 

class UserManagerImpl(implicit inj: Injector) extends UserManager with Injectable { 
    val profileManager = inject [ProfileManager] 

    def register(email: String, password: String) = ??? 
} 

class UserService(implicit inj: Injector) extends Actor with AkkaInjectable { 
    val userManager = inject [UserManager] 

    import UserService._ 

    def receive = { 
    case Register(email, password) => 
     userManager 
    } 
} 

object UserService { 
    case class Register(email: String, password: String) 
} 

class ReceptionistService(implicit inj: Injector) extends Actor with AkkaInjectable { 
    val userManager = injectActorRef [UserService] 
    def receive = ??? 
} 

주의 사항 : 여기 일반 바인딩 및 ActorRefs를 주입 할 수있는 방법의 작은 예입니다.따라서 상응하는 다음과 같습니다

val userManager = context.actorOf(injectActorProps[UserService]) 

는 이제 ActorSystem (이것은 선택 사항, 그리고 당신이 플레이를 사용하는 경우, 당신은 아마 이미 하나를 가지고 플레이 응용 프로그램에서 ActorSystem을 얻을 필요가 바인딩을 작성해야), 귀하의 경우 배우 서비스() 및 관리자 :

implicit val module = new Module { 
    bind [ActorSystem] to ActorSystem("MySystem") 

    binding toProvider new UserService 
    binding toProvider new ReceptionistService 

    bind [UserManager] to new UserManagerImpl 
    binding to new ProfileManager 
} 

그것은 toProvider으로 Actor들에 결합하는 것이 중요하다. 그러면 Akka가 Scaldi에게 특정 Actor을 요청할 때마다 항상 그 인스턴스가 새로 생성됩니다. 당신이 ReceptionistService이 최상위 배우가 되길 원한다면

이제,이처럼 사용할 수 있습니다

implicit val system = inject [ActorSystem] 

val receptionist = injectActorRef [ReceptionistService] 

receptionist ! DoStuff 

를이 경우, system의 보호자 배우가 감독의 것이다.