2016-07-20 1 views
1

Я работаю над Playframework2.5 с помощью play-slick и связанных с ним программ, таких как пакет.Создайте экземпляр класса, который делает DI через Playframework Guice Независимо в Scala

текущая структура проекта как

/rootPlayProject 
    /app 
    /controllers 
    /filters 
    /services 
    ... 
    Modules 
    /core (sub-project - DAOs,services are placed here) 
    /batch (sub-project depends on core) 

Я использую Guice DI почти везде включают в себя объект доступа к базе данных (DAO). И интерфейсы в ядре связаны в Module, размещенном в core, который в конечном итоге получает унаследованный Module в корневом проекте.

Основной модуль (/rootPlayProject/core/CoreModule.scala)

class CoreModule extends AbstractModule { 
    override def configure() = { 
    bind(classOf[FooDAO]).to(classOf[FooDAOImpl]) 
    .... 
    } 
} 

Корневой модуль (/rootPlayProject/Modules.scala)

class Module extends CoreModule { 
    override def configure() = { 
    super.configure() 
    bind(classOf[FooService]).to(classOf[FooServiceImpl]) 
    } 
} 

Это работает очень хорошо, как приложение Playframework, хотя, я хотел бы использовать основной модуль для пакетных программ, и я хотел бы запускать партии без playframework.

до сих пор я пытался что-то вроде этого

object BatchA { 
    def main(args: Array[String]) = { 
    val injector = Guice.createInjector(new CoreModule) 
    val foo = injector.getInstance(classOf[FooDAO]) 
    //do something with foo. 
    } 
} 

но так как требующие вещи моего DAO в Playframework создавать такие как ExecutionContext, play.api.db.slick.DatabaseConfigProvider и @play.db.NamedDatabase, выше код не работает.

Мой вопрос: как я могу позволить этим вещам связать себя без создания игрового приложения?

Заранее спасибо.

ответ

0

GuiceInjectorBuilder сделать трюк.

trait PlayInjector { 
    lazy val injector = new GuiceInjectorBuilder().configure(Configuration.load(Environment.simple(mode = Mode.Dev))) 
    .bindings(new BuiltinModule, new CoreModule, new SlickModule).disable(classOf[Application]).injector 

    def closeInjector = injector.instanceOf[DefaultApplicationLifecycle].stop 
} 

BuiltinModule связывает Play основные модули, такие как ExecutionContext, ExecutionContextExecutor или ActorSystem. Вы можете сделать свой собственный модуль привязанным только к тем вещам, которые вам нужны, но с помощью BuiltinModule и отключить классы, которые вам не нужны, проще.

, как использовать его

object Foo extends PlayInjector { 
    def main(args: Array[String]) = { 
    val foo = injector.instanceOf[FooDAO] 
    val bar = injector.instanceOf[BarDAO] 
    //do something 
    //when you finish things you want to do 
    closeInjector 
    } 
} 

Поскольку некоторые модули, такие как PlaySlick использует ApplicationLifecycle.addStopHook для обработки закрытия операции. Безопаснее выполнять их, а не просто звонить sys.exit()

1

Ответ зависит от того, хотите ли вы фактически отделить Play Framework от своих DAO.

Вариант 1: Не Отделить

Ваш основной метод могли бы просто следующие строки вашей val injector предшествующего линии:

val application = new GuiceApplicationBuilder() 
    .in(Environment(new File("."), this.getClass.getClassLoader, Mode.Prod)) 
    .build 
Play.start(application) 

Вариант 2: Отделить

Или, вы можете предоставить классы для инъекций, которые могут предоставить ExecutionContext, специфичные для среды. Если вы хотите ввести DatabaseConfigProvider, вам придется выполнять дополнительные абстракции, чтобы удалить прямую зависимость от Play. Аннотация будет следовать за реализацией абстракции, специфичной для Play.


В случае моего собственного проекта, где я столкнулся этот сценарий, я выбрал вариант 1, так как зависимость от игры не было достаточно воздействия для меня тяжелой.

+0

случай «Option1» означает, что приложение для воспроизведения работает, а я делаю то, что хочу, правильно? Если это не слишком сложно сделать, я предпочитаю последний, поэтому мне не нужно запускать игровое приложение для выполнения просто пакета. – suish

+0

В вашем случае вариант 2 может быть более разумным. – doctorless