2017-01-04 2 views
0

Je ne suis pas capable de comprendre comment injecter un service dans un acteur.injecter le service dans l'acteur donne NullPointerException

J'ai essayé plusieurs approches et je pense que celle-ci devrait être la meilleure.

Je pense que le problème majeur est que je fournis la socket Web à l'acteur suivant en tant que paramètre. Lorsque je tire l'Inject jusqu'à la compilation de la signature de classe ne fonctionne pas à cause du conflit de signature. J'ai essayé d'ajouter une déclaration de classe implicite pour injecter le service, mais cela n'a pas fonctionné non plus.

Que dois-je faire pour bien faire les choses?

L'exécution de ce code entraîne une exception NullPointerException.

package actors 

import akka.actor._ 
import com.google.inject.Inject 
import play.api.libs.json._ 
import models._ 
import services.WeatherService 

/** 
    * Created by jbc on 28.12.16. 
    */ 
class WeatherWSActor (out: ActorRef) extends Actor { 

    @Inject() val weatherService: WeatherService = null 

    def handleMessage(msg: JsValue): JsValue = { 

    val req = msg.as[Request] 

    req match { 
     case Request("daily") => Json.toJson(weatherService.getFourDays()) 
     case Request("next") => Json.toJson(weatherService.getNextHour()) 
    } 
    } 

    override def receive: Receive = { 
    case msg: JsValue => out ! handleMessage(msg) 
    case _ => out ! "Bad Request" 
    } 

    @scala.throws[Exception](classOf[Exception]) 
    override def postStop(): Unit = { 

    } 
} 

object WeatherWSActor { 
    def props(out: ActorRef) = Props(new WeatherWSActor(out)) 
} 

Code du contrôleur:

class WeatherWSController @Inject() (implicit system: ActorSystem, materializer: Materializer) extends Controller { 

    def socket = WebSocket.accept[JsValue, JsValue] { request => 
    ActorFlow.actorRef(out => WeatherWSActor.props(out)); 
    } 

} 

Le service est mis en place avec ce code de module

class Module extends AbstractModule { 
    override def configure(): Unit = { 
     bind(classOf[WeatherService]).to(classOf[WeatherServiceImpl]).asEagerSingleton() 
    } 
} 

Répondre

0

Ceci est couvert dans le documentation, mais voici un résumé.

Si vous voulez injecter vos acteurs, vous devez changer certaines choses. Tout d'abord, le point d'injection est le constructeur, donc

class WeatherWSActor (out: ActorRef) extends Actor { 
    @Inject() val weatherService: WeatherService = null 
    // ... 
} 

devrait devenir

class WeatherWSActor @Inject() (out: ActorRef, 
           weatherService: WeatherService) extends Actor { 
    // ... 
} 

En fait, l'attribution null à une Scala val va également vous donner des problèmes.

Ensuite, déclarez une liaison pour l'acteur au lieu de le créer vous-même.

import com.google.inject.AbstractModule 
import play.api.libs.concurrent.AkkaGuiceSupport 

import actors.WeatherWSActor 

class MyModule extends AbstractModule with AkkaGuiceSupport { 
    def configure = { 
    bindActor[WeatherWSActor]("weather-actor") 
    } 
} 

Sur une note de côté, vous aurez également besoin de créer un nom de liaison pour out et changer la définition de WeatherWSActor pour refléter ceci:

class WeatherWSActor @Inject() (@javax.inject.Named("out-actor") out: ActorRef, 
           weatherService: WeatherService) extends Actor { 
    // ... 
} 

out-actor est selon la classe que vous avez mis en place le module, par exemple

class MyModule extends AbstractModule with AkkaGuiceSupport { 
    def configure = { 
    bindActor[WeatherWSActor]("weather-actor") 
    bindActor[SomeOutActor]("out-actor") 
    } 
} 

Mais ...

Puisque vous obtenez out quand un socket web est créé, vous êtes (probablement) va avoir plusieurs instances WeatherWSActor. Cela va affecter la façon dont vous gérez l'injection de dépendance, il est donc plus logique de ne pas injecter outActor (et donc de ne pas créer de lien pour cela), mais plutôt d'un singleton WeatherWSActor qui diffuse à toutes les instances de OutActor adressées à un certain point dans le système d'acteur.