Tomcat: javax.naming.NoInitialContextException

4

我有一个基于Java Servlets的webservice,它运行在Tomcat服务器上。 在我的Servlet中,我使用类似如下的数据库池:

envContext = new InitialContext();
DataSource ds = (DataSource) envContext.lookup( "java:/comp/env/jdbc/Database" );
con = ds.getConnection();

对于初始化,我在我的web.xml文件中有以下设置:

<resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/Database</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

接下来是 context.xml,这似乎是关键的一步:

<?xml version="1.0" encoding="UTF-8"?>
 <!-- The contents of this file will be loaded for each web application -->
  <Context crossContext="true">

    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>

   <Resource name="jdbc/Database" auth="Container"
        type="javax.sql.DataSource"
        maxActive="100" maxIdle="30" maxWait="10000"
        username="user" 
        password="password" 
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/configerror_db"/>
</Context>

我看到了很多关于这个错误的问题,但是我无法解决它。

首先我想解释一下,当我使用我的Linux机器时,我没有遇到这个错误。然而,当我在我的Windows机器上使用Eclipse安装了相同的代码时,我就会遇到这个上下文环境错误。

其他答案建议这样做。

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, 
    "<initialContextFactory>");
env.put(Context.PROVIDER_URL, "<url>");
env.put(Context.SECURITY_PRINCIPAL, "<user>");
env.put(Context.SECURITY_CREDENTIALS, "<password>");
ctx = new InitialContext(env);

但是我不知道什么是initialContextFactory,而且context.xml难道不应该做这件事吗?就像我在Linux上说的那样,它可以工作。
有人能帮我解决一下吗?我错过了什么?我不想在每个使用数据库连接的文件中编写用户名和密码。我认为这很棒。凭据只需在context.xml中,但现在在Windows上它不起作用。
感谢任何建议。

1
异常强烈暗示Tomcat实例中禁用了JNDI。你无法从Web应用程序端启用它。此时,你所能做的就是联系负责服务器管理的管理员以获取详细信息(询问为什么禁用以及他们提出的替代方案)。顺便提一下,建议的代码片段只适用于Java SE应用程序,而不适用于Java EE应用程序,因为服务器本身负责此项任务,而不是部署的Web应用程序(也不能这样做)。 - BalusC
1
除非您在Tomcat容器中运行,否则此代码将无法工作。两台机器上都是这种情况吗? - user207421
@EJP:我对Java Servlets和Tomcat非常陌生。我只是使用Eclipse来运行我的代码和Tomcat服务器。我在两台机器上都这样做。 - progNewbie
3个回答

3

您好,progNewbie。

我正在使用 Windows 操作系统Eclipse 集成开发环境,特别是在与您所寻找的相同类型项目上工作。

您需要在以下位置更新您的代码(3 处更改)...

1. 进行以下 Java 更改:

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
......
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/Database");
conn = ds.getConnection();

2. 同样地,配置Java Web应用程序的web.xml文件

请注意,保留原始的HTML标签。
......
  <resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/Database</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
......... 

3. 在Tomcat的server.xml文件中进行以下更改:

..................
<!-- Assume my application runs on localhost... -->
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">

<Valve className=..../>

<Context docBase="...." path="..." reloadable="true" source=".....">

<!-- Assume i am using Oracle Database so that driverClass(below) Attribute's Value will be oracle.jdbc.driver.OracleDriver -->
<Resource auth="Container" driverClassName="oracle.jdbc.driver.OracleDriver" 
    maxActive="100" maxIdle="30" maxWait="10000" name="jdbc/Database" password="db-password" 
    type="javax.sql.DataSource" url="db-connection-url" username="db-user-name" 
/>

</Context>

</Host>
............

编辑:

在此输入图片描述

如果还有问题,请告诉我。


你是在使用Eclipse+Tomcat吗?那么server.xml文件应该在Tomcat内部。 - Vishal Gajera
@progNewbie,你是对的,第二点是你代码的镜像。为了桥接所有必需的配置,我在这里包含了它。 - Vishal Gajera
@progNewbie 不,你正在走向正确的方向。你能否按照我将这些部分添加到我的问题中的“编辑”部分的方式进行操作? - Vishal Gajera
@progNewbie,请查看我的已编辑部分,这将帮助您从 Eclipse IDE 中获取 server.xml 文件。 - Vishal Gajera
让我们在聊天室中继续这个讨论 - Vishal Gajera
显示剩余3条评论

-1

更新:

initialContextFactory 是什么,它的作用是什么?

初始上下文工厂

保持环境属性名称的常量,用于指定要使用的初始上下文工厂。该属性的值应为将创建初始上下文的工厂类的完全限定类名。此属性可以在传递给初始上下文构造函数的环境参数、小程序参数、系统属性或应用程序资源文件中指定。

如果未在这些来源中指定,则在需要完成操作时抛出 NoInitialContextException 异常。

此常量的值为 "java.naming.factory.initial"

更多详情请参考教程


服务器管理员工作区:

当服务器管理员创建数据源时,他将其与配置为访问特定供应商数据库的Java数据库连接(JDBC)提供程序相关联。应用服务器需要这两个对象,以便您的应用程序调用该特定数据库并从中接收数据。数据源提供连接管理功能,从而在您的应用程序和数据库之间实现这些交换。

必须重新启动服务器,才能使新创建的数据源对应用程序中的Java命名和目录接口(JNDI)可用。

在服务器配置中,有一个名为jndi名称的选项。服务器管理员在JNDI名称字段中输入Java命名和目录接口(JNDI)名称。应用服务器使用JNDI名称将资源引用绑定到此数据源的应用程序。

注意:

  1. 不要在不同的资源类型之间分配重复的JNDI名称,例如数据源与J2C连接工厂或JMS连接工厂。
  2. 不要在相同范围内为多个相同类型的资源分配重复的JNDI名称。

资源链接:

使用管理控制台配置数据源


开发人员工作区:

为任何Java Web应用程序配置和运行JNDI数据源连接池有三个步骤:

  • 在服务器上配置数据源并创建JNDI名称。
  • 配置web.xml
  • 使用JNDI数据源配置您的bean
  • 在服务器库中包含JDBC驱动程序库

数据库方面的配置和代码在这里给出。

资源链接:

  1. Apche Tomcat 7中的JNDI资源HOW-TO
  2. 如何在Tomcat 6中配置MySQL数据源


正如@BalusC所说,

异常强烈暗示Tomcat实例上已禁用JNDI。

因此为启用JNDI,您可以获取许多教程。

有关启用JNDI的更详细说明,包括示例,请单击此处

您还可以通过本教程了解更多信息。

资源链接:

  1. Tomcat DataSource JNDI示例

1
这些链接并没有展示如何在Tomcat中启用JNDI。这些链接只展示了如何在部署到Tomcat的Web应用程序中使用JNDI。此外,您应该在帖子中包含真正的答案,而不是将其“隐藏”在链接后面。现在看起来太像“盲猜”。一个答案应该能够自己站立,并且仍然回答具体问题,而不需要单击其中任何链接。 - BalusC

-1

您在web.xmlcontext.xml中的配置是正确的。没有必要通过填充HashTable的代码来重现它。

我已经成功地测试了类似的实验。问题可能很简单,就是您的JNDI URL中有一个斜杠太多了:请尝试这个:

DataSource ds = (DataSource) envContext.lookup( "java:comp/env/jdbc/Database" ); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接