2

我正在将我的应用程序从 play 2.3 迁移到 2.4。

在 GlobalSettings 的 2.3 应用程序中,我必须使用 slick 访问数据库来创建 postgres 数据库函数。

由于 GlobalSettings 在 2.4 中已弃用,因此替代方法是使用 Eager Bindings:

https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection#Eager-bindings

像这样:

class MyModule extends AbstractModule {
  def configure() = {
    db.withSession { implicit ss =>
      StaticQuery.update("""CREATE OR REPLACE FUNCTION ... """).execute
    }
  }
}

但这给了我错误:

java.lang.ExceptionInInitializerError: 
     core.includes$.<init>(includes.scala:14)
     core.includes$.<clinit>(includes.scala)
     Application$$anonfun$configure$1.apply(Application.scala:17)
     Application$$anonfun$configure$1.apply(Application.scala:15)
     scala.slick.backend.DatabaseComponent$DatabaseDef$class.withSession(DatabaseComponent.scala:34)
     scala.slick.jdbc.JdbcBackend$DatabaseFactoryDef$$anon$4.withSession(JdbcBackend.scala:61)
     modules.jdbc.Database$$anonfun$withSession$1.apply(Database.scala:14)
     modules.jdbc.Database$$anonfun$withSession$1.apply(Database.scala:14)
     Application.configure(Application.scala:15)
     com.google.inject.AbstractModule.configure(AbstractModule.java:62)
     com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:340)
     com.google.inject.spi.Elements.getElements(Elements.java:110)
     com.google.inject.util.Modules$OverrideModule.configure(Modules.java:177)
     com.google.inject.AbstractModule.configure(AbstractModule.java:62)
     com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:340)
     com.google.inject.spi.Elements.getElements(Elements.java:110)
     com.google.inject.internal.InjectorShell$Builder.build(InjectorShell.java:138)
     com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:104)
     com.google.inject.Guice.createInjector(Guice.java:96)
     com.google.inject.Guice.createInjector(Guice.java:73)
     com.google.inject.Guice.createInjector(Guice.java:62)
     play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:126)
     play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:93)
     play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)

有谁知道我该如何解决这个问题?谢谢。

4

1 回答 1

6

根据引用自https://www.playframework.com/documentation/2.4.2/GlobalSettings:</p>

GlobalSettings.beforeStart 和 GlobalSettings.onStart:启动时需要发生的任何事情现在都应该在依赖注入类的构造函数中发生。一个类将在依赖注入框架加载它时执行它的初始化。如果您需要预先初始化(因为您需要在应用程序实际启动之前执行一些代码),请定义一个预先绑定。

如您所见,只有在应用程序启动之前需要发生某些事情时才能使用急切绑定,这不适用于您的情况,因为 db.withSession 需要启动的应用程序上下文。这就是发生异常的原因(严格来说,您没有以适当的方式使用急切绑定)。

那么如何才能实现目标呢?答案在引文的前两句。

首先,您必须定义如下内容:

@Singleton
class DatabaseService {
    db.withSession { implicit ss =>
      StaticQuery.update("""CREATE OR REPLACE FUNCTION ... """).execute
    }
}

然后如果将DatabaseService注入到另一个单例类中(最好注入到另一个单例类中,否则代码可能会被多次调用),而后面的类被Guice初始化,DatabaseService的构造函数中的代码是调用(因为 DatabaseService 首先被 Guice 初始化为后一个类的依赖项)。

例如,您可以将其注入控制器:

@Singleton
class Application @Inject() (dbService: DatabaseService) extends Controller {
  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }
}

然后如果有人访问索引页面,您的代码将被执行。

编辑:

我在该主题上找到了另一篇 stackoverflow 帖子,请参见此处:PlayFramework 2.4 run some code after application has started。它找出了在应用程序启动后运行代码的正确方法,同时仍然使用急切绑定。:)

如果您依赖于 ActorSystem,只需将 actorSystem: ActorSystem 注入您的类,如下所示:

@Singleton
class QuartzSchedulerService @Inject() (configuration: Configuration,
                                        actorSystem: ActorSystem,
                                        @Named("library.actors.ApiExecutionRecorderRouter") apiExecutionRecorderRouter: ActorRef
                                        ) {
  val scheduler = QuartzSchedulerExtension(actorSystem)
  scheduler.schedule("QuartzSchedulerTest", apiExecutionRecorderRouter, "Start")
}
于 2015-07-24T05:59:27.063 回答