Play 2.6.x Java 应用程序在开发模式下工作,但在生产模式下失败

Posted

技术标签:

【中文标题】Play 2.6.x Java 应用程序在开发模式下工作,但在生产模式下失败【英文标题】:Play 2.6.x Java Application works in Dev Mode but fails in Prod mode 【发布时间】:2017-11-15 18:17:44 【问题描述】:

我无法在生产模式下运行我的应用程序,而开发模式工作正常但找不到原因。

我正在使用 Play Framework 2.6.x 并连接到 Postgresql 数据库。

这是 sbt run 的输出(启动开发模式)

sbt run    
--- (Running the application, auto-reloading is enabled) ---

[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Enter to stop and go back to the console...)

[info] application - Creating Pool for datasource 'default'
[info] p.a.d.DefaultDBApi - Database [default] connected at jdbc:postgresql://192.168.155.177/legato
[info] a.e.s.Slf4jLogger - Slf4jLogger started
[info] play.api.Play - Application started (Dev)

这里是sbt start(启动生产模式)的输出

sbt start
(Starting server. Type Ctrl+D to exit logs, the server will remain in background)

[info] application - Creating Pool for datasource 'default'
[info] p.a.d.DefaultDBApi - Database [default] connected at jdbc:postgresql://192.168.155.177/legato
[info] a.e.s.Slf4jLogger - Slf4jLogger started
[warn] o.h.v.m.ParameterMessageInterpolator - HV000184: ParameterMessageInterpolator has been chosen, EL interpolation will not be supported
Oops, cannot start the server.
com.google.inject.CreationException: Unable to create injector, see the following errors:

1) Error injecting constructor, org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
  at play.db.jpa.DefaultJPAApi$JPAApiProvider.<init>(DefaultJPAApi.java:40)
  at play.db.jpa.DefaultJPAApi$JPAApiProvider.class(DefaultJPAApi.java:35)
  while locating play.db.jpa.DefaultJPAApi$JPAApiProvider

1 error
        at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:470)
        at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:184)
        at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
        at com.google.inject.Guice.createInjector(Guice.java:99)
        at com.google.inject.Guice.createInjector(Guice.java:84)
        at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:185)
        at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:137)
        at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
        at play.core.server.ProdServerStart$.start(ProdServerStart.scala:51)
        at play.core.server.ProdServerStart$.main(ProdServerStart.scala:25)
        at play.core.server.ProdServerStart.main(ProdServerStart.scala)
Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:271)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:233)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210)
        at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:51)
        at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:94)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:242)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210)
        at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.handleTypes(MetadataBuildingProcess.java:352)
        at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:111)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:858)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:885)
        at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:58)
        at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
        at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39)
        at play.db.jpa.DefaultJPAApi.lambda$start$1(DefaultJPAApi.java:61)
        at java.lang.Iterable.forEach(Iterable.java:75)
        at play.db.jpa.DefaultJPAApi.start(DefaultJPAApi.java:60)
        at play.db.jpa.DefaultJPAApi$JPAApiProvider.<init>(DefaultJPAApi.java:47)
        at play.db.jpa.DefaultJPAApi$JPAApiProvider$$FastClassByGuice$$dcd4cdbd.newInstance(<generated>)
        at com.google.inject.internal.DefaultConstructionProxyFactory$FastClassProxy.newInstance(DefaultConstructionProxyFactory.java:89)
        at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:111)
        at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:90)
        at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:268)
        at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
        at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092)
        at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
        at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:194)
        at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41)
        at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:205)
        at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:199)
        at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1085)
        at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(InternalInjectorCreator.java:199)
        at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:180)
        ... 9 more
Caused by: org.hibernate.engine.jndi.JndiException: Unable to lookup JNDI name [DefaultDS]
        at org.hibernate.engine.jndi.internal.JndiServiceImpl.locate(JndiServiceImpl.java:100)
        at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.configure(DatasourceConnectionProviderImpl.java:98)
        at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:94)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:242)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210)
        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.buildJdbcConnectionAccess(JdbcEnvironmentInitiator.java:145)
        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:66)
        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
        at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:88)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:259)
        ... 41 more
Caused by: javax.naming.NameNotFoundException: DefaultDS not found
        at tyrex.naming.MemoryContext.internalLookup(Unknown Source)
        at tyrex.naming.MemoryContext.lookup(Unknown Source)
        at javax.naming.InitialContext.lookup(InitialContext.java:421)
        at org.hibernate.engine.jndi.internal.JndiServiceImpl.locate(JndiServiceImpl.java:97)
        ... 50 more
[info] a.a.CoordinatedShutdown - Starting coordinated shutdown from JVM shutdown hook
[INFO] [11/15/2017 18:13:25.905] [Thread-2] [CoordinatedShutdown(akka://sbt-web)] Starting coordinated shutdown from JVM shutdown hook

谁能指出这个错误可能来自的方向?

这是我的application.conf

# This is the main configuration file for the application.
# https://www.playframework.com/documentation/latest/ConfigFile


# Point JPA at our database configuration
jpa.default=defaultPersistenceUnit

# Number of database connections
# See https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
fixedConnectionPool = 9

play.http.secret.key="xxxxxxxx"

db.default 
  driver = org.postgresql.Driver
  url = "jdbc:postgresql://192.168.155.177/legato"
  username = "vagrant"
  password = "xxxxxxx"


ebean.default = ["models.*"]

play.evolutions.enabled=true

# disable the built in filters
play.http.filters = play.api.http.NoHttpFilters

# Job queue sized to HikariCP connection pool
post.repository 
  executor = "thread-pool-executor"
  throughput = 1
  thread-pool-executor 
    fixed-pool-size = $fixedConnectionPool
  

还有我的 build.sbt

name := """Legato Core Backend"""

version := "stable"

inThisBuild(
  List(
    scalaVersion := "2.12.3",
    dependencyOverrides := Seq(
       "org.codehaus.plexus" % "plexus-utils" % "3.0.18",
       "com.google.code.findbugs" % "jsr305" % "3.0.1",
       "com.google.guava" % "guava" % "22.0",
       "com.typesafe.akka" %% "akka-stream" % "2.5.6",
       "com.typesafe.akka" %% "akka-actor" % "2.5.6"
    )
  )
)

lazy val root = (project in file(".")).enablePlugins(PlayJava, PlayEbean)

libraryDependencies += guice
libraryDependencies += javaJpa
libraryDependencies += evolutions
libraryDependencies += javaJdbc
libraryDependencies += "org.postgresql" % "postgresql" % "42.1.4"
libraryDependencies += "com.h2database" % "h2" % "1.4.194"

libraryDependencies += "org.hibernate" % "hibernate-core" % "5.2.9.Final"
libraryDependencies += "io.dropwizard.metrics" % "metrics-core" % "3.2.1"
libraryDependencies += "com.palominolabs.http" % "url-builder" % "1.1.0"
libraryDependencies += "net.jodah" % "failsafe" % "1.0.3"

libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % "2.3.0" % Test
libraryDependencies += "io.gatling" % "gatling-test-framework" % "2.3.0" % Test

PlayKeys.externalizeResources := false

testOptions in Test := Seq(Tests.Argument(TestFrameworks.JUnit, "-a", "-v"))

还有我的 plugins.sbt

// The Play plugin
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.6")

// Load testing tool:
// http://gatling.io/docs/2.2.2/extensions/sbt_plugin.html
addSbtPlugin("io.gatling" % "gatling-sbt" % "2.2.2")

addSbtPlugin("com.typesafe.sbt" % "sbt-play-enhancer" % "1.2.2")
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "4.0.6")

【问题讨论】:

【参考方案1】:

在您的build.sbt 中设置PlayKeys.externalizeResources := false。来自documentation:

使用 JPA 部署 Play

在使用 JPA 时在开发模式下运行 Play 可以正常工作,但为了部署应用程序,您需要将其添加到您的 build.sbt 文件中。

PlayKeys.externalizeResources := false

注意:从 Play 2.4 开始默认将 conf 目录的内容添加到类路径中。此选项将禁用该行为并允许部署 JPA 应用程序。由于 conf 目录的内容已包含在应用程序的 jar 文件中,因此类路径中的内容仍然可用。

【讨论】:

以上是关于Play 2.6.x Java 应用程序在开发模式下工作,但在生产模式下失败的主要内容,如果未能解决你的问题,请参考以下文章

Java Play 框架中的观察者模式

Play Framework:生产和开发模式下的不同图标

如何搭建scala的play框架

在 Play dev 和 prod 模式下访问文件

如何在 Play Framework 2 应用程序的生产模式下进行热重新部署?

设置 Play 框架环境