【问题标题】:Inject database dependency scala Object注入数据库依赖scala对象
【发布时间】:2017-04-16 19:05:45
【问题描述】:

有没有办法在 Scala 对象中注入 play 数据库依赖项?我知道我们可以在课堂上做到这一点

class MyClass @Inject() (db: Database) = {
}

但我想在不实际使用 Play 插件的情况下注入依赖项。

我的 build.sbt 看起来像这样

scalaVersion := "2.11.8"

lazy val sparkVersion = "2.1.0"

lazy val hadoopVersion = "2.7.0"

lazy val jacksonVersion = "2.8.7"

libraryDependencies ++= Seq(
  "org.apache.spark" %% "spark-core" % sparkVersion,
  "org.apache.spark" %% "spark-sql" % sparkVersion,
  "org.apache.hadoop" % "hadoop-common" % hadoopVersion,
  "com.databricks" %% "spark-csv" % "1.5.0",
  "org.codehaus.janino" % "janino" % "3.0.7",
  "com.databricks" % "spark-redshift_2.11" % "3.0.0-preview1",
  "com.amazonaws" % "aws-java-sdk-s3" % "1.11.34",
  "com.typesafe" % "config" % "1.3.1",
  "com.typesafe.play" % "play-json_2.11" % "2.4.6",
  "com.typesafe.play" %% "play" % "2.5.9",
  "com.typesafe.play" % "play-jdbc_2.11" % "2.5.14",
  "com.amazon.redshift" % "jdbc42" % "1.2.1.1001" from "https://s3.amazonaws.com/redshift-downloads/drivers/RedshiftJDBC42-1.2.1.1001.jar"
)

fork in Test := true

assemblyMergeStrategy in assembly := {
  case ".gitkeep" => MergeStrategy.discard
  case "META-INF/groovy-release-info.properties" => MergeStrategy.discard
  case "META-INF/MANIFEST.MF" => MergeStrategy.discard
  //case "log4j.properties" => MergeStrategy.deduplicate
  case x: String if x.matches( """META-INF/.*\.(SF|DSA|RSA)""") => MergeStrategy.discard
  case x: String if x.startsWith("META-INF/services/org.apache.lucene") => MergeStrategy.concat
  case x => MergeStrategy.first
}

我试过了

object MyObject {
@Inject()
var db: Database = _
}

但因空指针异常而失败

【问题讨论】:

  • 根据我的卑微经验:通常你不想将状态存储在object。因此,您不想以其他方式将状态注入对象,而不仅仅是在方法调用中传递它。这样你就没有初始化问题,改变注入的依赖项的行为也没有问题,事情仍然是可测试的。

标签: scala dependency-injection


【解决方案1】:

@Inject 在这种情况下不起作用。 Object 在语言级别上作为单例工作,而依赖注入是配置驱动的,在 Playframework 的情况下,它是在下面使用 Guice 引擎构建的。实际上,DI 仅适用于由 DI 创建或插入其中的对象,因此Guice 至少应该知道MyObject 的存在。

最好的选择是使用带有@Inject注解的类

 case class MyObject @Inject() (db: Database)

如果不是这种情况,您可以从 Application 对象获取 Injector 引用(已弃用,应避免使用)

object MyObject {
   lazy val db: Database = Play.unsafeApplication.injector.instanceOf[Database]
}

【讨论】:

  • 当我按照你说的使用 Injector 时,它会抛出“应用程序未启动”错误
  • 您需要运行一个应用程序。 val db之前有懒惰吗?
  • 是的。实际上它是没有 Play 插件的 Spark 应用程序。但我想使用 Play 特定功能,例如注入数据库、配置来读取 application.conf、环境等,而无需在 build.sbt 中实际启用 Play 插件。到目前为止阅读 application.conf 我正在使用 ConfigFactory i/o 配置。有没有办法在不使用 Play 插件的情况下使用这些?
  • 如果我将其声明为 Class,我可以注入依赖。但是要运行 spark 作业,我们需要在对象中声明 main 方法,否则会引发错误。例如我有类 MyClass @Inject() (config: Configuration) 类,我正在读取 application.conf 中声明的所有变量,但我无法在 Spark 应用程序的 main 方法中访问它们。
  • 我建议使用静态 Guice 上下文,您可以从中读取依赖项。您可以实例化 GuiceApplicationBuilder,就像在 Play 中所做的那样,或者根据需要创建单独的模块。 Play 负责在下面运行 Guice,如果您不想启动应用程序,则必须自己处理
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
  • 2023-04-09
相关资源
最近更新 更多