首页 > 解决方案 > 尝试从数据库中检索数据时出现 NoInitialContextException。Heroku Java Web 应用程序

问题描述

我是一个通常通过自己研究和尝试来解决问题的人(这就是为什么我在这里的问题为零)。但是,我已经浪费了几天时间试图弄清楚这一点,而且我别无选择。我希望你们能帮助我。我正在尝试让我的 Java/Maven/Hibernate/JPA/Tomcat Web 应用程序在免费的 Heroku 帐户上运行。我能够成功部署并将一些数据发送到 Heroku Postgres DB。在本地服务器 (Tomcat/IntelliJ) 上运行的相同应用程序可以成功连接并从 Heroku 数据库中检索数据。但是,部署的 Heroku 应用程序无法使用 Heroku 数据库。该应用程序运行良好,但是当它尝试从数据库中检索数据时出现错误。

我在这里搜索了与此错误相关的解决方案以及下面堆栈中的其他解决方案,包括已经建议的解决方案:NoInitialContextException 错误的含义。似乎没有一个适合我的情况。上面的链接提到使用 Properties 对象,但正如我所提到的,它在本地工作正常,我以前从未使用过这样的对象。如果您认为这可能是一个解决方案,您能否提供有关如何在我的环境中实施该解决方案的更多详细信息?

我没有 Procfile 设置,我正在使用以下 Heroku 命令部署应用程序:

heroku war:deploy target/appname.war --app appname

这是我得到的错误堆栈(来自启用了调试日志的 Heroku 日志):

2021-07-18T19:27:42.218347+00:00 app[web.1]: SEVERE: Servlet.service() for servlet [AdminServlet] in context with path [] threw exception [Servlet execution threw an exception] with root cause
2021-07-18T19:27:42.218348+00:00 app[web.1]: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
2021-07-18T19:27:42.218349+00:00 app[web.1]:    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:673)
2021-07-18T19:27:42.218349+00:00 app[web.1]:    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
2021-07-18T19:27:42.218350+00:00 app[web.1]:    at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:350)
2021-07-18T19:27:42.218350+00:00 app[web.1]:    at javax.naming.InitialContext.getNameParser(InitialContext.java:505)
2021-07-18T19:27:42.218358+00:00 app[web.1]:    at org.hibernate.engine.jndi.internal.JndiServiceImpl.parseName(JndiServiceImpl.java:118)
2021-07-18T19:27:42.218358+00:00 app[web.1]:    at org.hibernate.engine.jndi.internal.JndiServiceImpl.locate(JndiServiceImpl.java:95)
2021-07-18T19:27:42.218359+00:00 app[web.1]:    at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.configure(DatasourceConnectionProviderImpl.java:98)
2021-07-18T19:27:42.218363+00:00 app[web.1]:    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:107)
2021-07-18T19:27:42.218363+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:246)
2021-07-18T19:27:42.218365+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
2021-07-18T19:27:42.218366+00:00 app[web.1]:    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.buildJdbcConnectionAccess(JdbcEnvironmentInitiator.java:145)
2021-07-18T19:27:42.218366+00:00 app[web.1]:    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:66)
2021-07-18T19:27:42.218366+00:00 app[web.1]:    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
2021-07-18T19:27:42.218366+00:00 app[web.1]:    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101)
2021-07-18T19:27:42.218367+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
2021-07-18T19:27:42.218367+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237)
2021-07-18T19:27:42.218367+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
2021-07-18T19:27:42.218368+00:00 app[web.1]:    at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152)
2021-07-18T19:27:42.218368+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286)
2021-07-18T19:27:42.218369+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243)
2021-07-18T19:27:42.218369+00:00 app[web.1]:    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
2021-07-18T19:27:42.218369+00:00 app[web.1]:    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:176)
2021-07-18T19:27:42.218370+00:00 app[web.1]:    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:127)
2021-07-18T19:27:42.218370+00:00 app[web.1]:    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1224)
2021-07-18T19:27:42.218370+00:00 app[web.1]:    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1255)
2021-07-18T19:27:42.218370+00:00 app[web.1]:    at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
2021-07-18T19:27:42.218371+00:00 app[web.1]:    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
2021-07-18T19:27:42.218371+00:00 app[web.1]:    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
2021-07-18T19:27:42.218376+00:00 app[web.1]:    at dataaccess.HibernateUtil.<clinit>(HibernateUtil.java:12)
2021-07-18T19:27:42.218376+00:00 app[web.1]:    at dataaccess.CityDB.getAllCities(CityDB.java:37)
2021-07-18T19:27:42.218376+00:00 app[web.1]:    at servlets.AdminServlet.doGet(AdminServlet.java:61)
2021-07-18T19:27:42.218377+00:00 app[web.1]:    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
2021-07-18T19:27:42.218377+00:00 app[web.1]:    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
2021-07-18T19:27:42.218378+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
2021-07-18T19:27:42.218378+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
2021-07-18T19:27:42.218378+00:00 app[web.1]:    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
2021-07-18T19:27:42.218386+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
2021-07-18T19:27:42.218387+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
2021-07-18T19:27:42.218387+00:00 app[web.1]:    at filters.AdminFilter.doFilter(AdminFilter.java:35)
2021-07-18T19:27:42.218387+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
2021-07-18T19:27:42.218388+00:00 app[web.1]:    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
2021-07-18T19:27:42.218388+00:00 app[web.1]:    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
2021-07-18T19:27:42.218388+00:00 app[web.1]:    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
2021-07-18T19:27:42.218389+00:00 app[web.1]:    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
2021-07-18T19:27:42.218389+00:00 app[web.1]:    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
2021-07-18T19:27:42.218389+00:00 app[web.1]:    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
2021-07-18T19:27:42.218389+00:00 app[web.1]:    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
2021-07-18T19:27:42.218390+00:00 app[web.1]:    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
2021-07-18T19:27:42.218390+00:00 app[web.1]:    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
2021-07-18T19:27:42.218391+00:00 app[web.1]:    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
2021-07-18T19:27:42.218391+00:00 app[web.1]:    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
2021-07-18T19:27:42.218391+00:00 app[web.1]:    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
2021-07-18T19:27:42.218391+00:00 app[web.1]:    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
2021-07-18T19:27:42.218392+00:00 app[web.1]:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
2021-07-18T19:27:42.218392+00:00 app[web.1]:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
2021-07-18T19:27:42.218392+00:00 app[web.1]:    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
2021-07-18T19:27:42.218393+00:00 app[web.1]:    at java.lang.Thread.run(Thread.java:748)

当我的应用程序中的任何类调用我的 HibernateUtil 类中的EntityManagerFactory方法时,就会发生错误。这是被调用的代码:

public class HibernateUtil {
    private static final EntityManagerFactory emf =
            Persistence.createEntityManagerFactory("AbsPu");

    public static EntityManagerFactory getEmFactory() {
        return emf;
    }
}

这就是我的 webapp/META-INF/ context.xml的样子(我删除了敏感数据)。在这里,我还尝试使用 Heroku 中的 DATABASE_URL 系统变量,而不是对 url 进行硬编码,但我不知道如何使它工作。但它是这样工作的:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/">
    <Resource name="jdbc/postgres" auth="Container"
              type="javax.sql.DataSource"
              driverClassName="org.postgresql.Driver"
              url="jdbc:postgresql://ec2-52-2-118-38.compute-1.amazonaws.com:5432/...?sslmode=require"
              username="..." password="..."
              maxActive="100" maxIdle="30" maxWait="10000"
              logAbandoned="true" removeAbandoned="true"
              removeAbandonedTimeout="60" />
</Context>

这就是我的 resources/META-INF/ persisence.xml的样子。同样,我刚刚删除了敏感数据(类名):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">
  <persistence-unit name="AbsPu">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <non-jta-data-source>java:/comp/env/jdbc/postgres</non-jta-data-source>
    <class>...</class>
    ...
    <class>...</class>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
  </persistence-unit>
</persistence>

最后,我的pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <version>1.0</version>
  <packaging>war</packaging>

  <name>...</name>
  <URL>...</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.4.30.Final</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.20</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>...</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <configuration>
                  <source>8</source>
                  <target>8</target>
              </configuration>
          </plugin>
      </plugins>
  </build>
</project>

我提供了我能想到的尽可能多的细节。如果您需要更多详细信息,请告诉我!

标签: javaxmlhibernatetomcatheroku

解决方案


终于解决了。这些是我为解决问题所做的步骤:

  1. 通过在初始化中添加“--enable-naming”来启用 JNDI 命名: heroku config:set WEBAPP_RUNNER_OPTS="--enable-naming" --app appname. 添加后,我开始收到另一个错误:java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory

  2. 基于新的错误,我在 context.xml 中指定了资源工厂: factory="org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory"

  3. 最后,向 pom.xml 添加了一个新的依赖项:

    <dependency>
          <groupId>org.apache.tomcat</groupId>
          <artifactId>tomcat-dbcp</artifactId>
          <version>10.1.0-M2</version>
    </dependency>
    

最后两步来自这个问题:SpringBoot JNDI datasource throws java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory

我相信 IntelliJ 默认情况下可以很好地使用 JNDI 命名,并且具有用于 Tomcat 的嵌入式数据库连接池 API。这可能就是为什么它在本地运行良好而不是在 Heroku 上运行良好的原因。


推荐阅读