6

Helo 大师,我必须动态创建一个 JNDI 数据源,我尝试使用一个名为 SetupApplicationListener 的侦听器来完成它。这里是开始WEB-LIB/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee">

    <display-name>pri-web</display-name>

    <!-- Listeners -->
    <listener>
        <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>myapp.SetupApplicationListener</listener-class>
    </listener>

监听器代码:

public class SetupApplicationListener implements ServletContextListener {

    public static Log LOG = null;

    public void contextInitialized(ServletContextEvent ctx){
        try {            
            createOracleDataSource();
.....
        }
    }

    private void createOracleDataSource() throws SQLException, NamingException {
        OracleDataSource ds = new OracleDataSource();
        ds.setDriverType(...);
        ds.setServerName(...);
        ds.setPortNumber(...);
        ds.setDatabaseName(...);
        ds.setUser(...);
        ds.setPassword(...);

        new InitialContext().bind("java:comp/env/jdbc/myDS", ds);
    }

.....
}

并且有错误:

[ERROR] 29/01/2013 09:44:50,517 (SetupApplicationListener.java:86) -> Error
javax.naming.NamingException: Context is read only
    at org.apache.naming.NamingContext.checkWritable(NamingContext.java:903)
    at org.apache.naming.NamingContext.bind(NamingContext.java:831)
    at org.apache.naming.NamingContext.bind(NamingContext.java:171)
    at org.apache.naming.NamingContext.bind(NamingContext.java:187)
    at org.apache.naming.SelectorContext.bind(SelectorContext.java:186)
    at javax.naming.InitialContext.bind(InitialContext.java:359)
    at myapp.SetupApplicationListener.createOracleDataSource(SetupApplicationListener.java:102)

我可以将 Context 的只读属性设置为“true”吗?谢谢!:)

Tomcat 6.0
Oracle 11g
jdk1.5

编辑:不需要动态,我必须在内部定义一个 jndi 数据源我不能修改服务器文件,因为它是一个共享服务器。它必须是 jndi 因为其他模块以这种方式使用它,谢谢。

4

7 回答 7

4

如果您需要动态创建数据源,是否真的需要 JNDI 查找?JNDI 旨在建立应用程序外部的连接,而在您的场景中,由于合法需求,它与应用程序紧密耦合。为什么不只使用 JDBC 连接?

于 2013-01-29T10:18:35.467 回答
4

您需要创建一个 ServletContextListener 并在那里您可以使 InitialContext 可写 - 这不是应该这样做的方式,但如果您真的需要它,这是您可以做到的一种方式。

这也适用于 Java Melody!

protected void makeJNDIContextWritable(ServletContextEvent sce) {
    try {
        Class<?> contextAccessControllerClass = sce.getClass().getClassLoader().loadClass("org.apache.naming.ContextAccessController");
        Field readOnlyContextsField = contextAccessControllerClass.getDeclaredField("readOnlyContexts");
        readOnlyContextsField.setAccessible(true);
        Hashtable readOnlyContexts = (Hashtable) readOnlyContextsField.get(null);
        String context = null;
        for (Object key : readOnlyContexts.keySet()) {
            String keyString = key + "";
            if (keyString.endsWith(sce.getServletContext().getContextPath())) {
                context = keyString;
            }
        }
        readOnlyContexts.remove(context);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}
于 2016-03-22T10:59:50.283 回答
2

我以前没有遇到过这个问题,因为我通常在应用程序服务器(tomcat、weblogic 等)中定义 JNDI。正如 Kevin 所说,这正是 JNDI 的设计目的;将数据源配置与源代码分离,并通过查找和注入检索 JNDI 资源;

回到您的问题,我认为 tomcat 对在运行时修改 JNDI 有严格的规定。换句话说,您不能从 Context 中重新绑定或删除 jndi。如果您仔细阅读 tomcat 规范,您可能会看到一些关于 jndi 查找但没有重新绑定的内容。

于 2013-01-29T10:27:25.280 回答
2

来自 EE 6 平台规范 (JSR 316) 的 EE.5.3.4 部分:

容器必须确保应用程序组件实例对其命名上下文只有读取权限。容器必须从修改环境命名上下文及其子上下文的 javax.naming.Context 接口的所有方法中抛出 javax.naming.OperationNotSupportedException。

请注意,本节中的“它们的命名上下文”指的是java:comp.

于 2013-01-29T16:23:25.047 回答
0

useNaming="false"我通过在我的 context.xml 中设置解决了这个问题。

从文档中

useNaming :设置为 true(默认值)以让 Catalina 为该 Web 应用程序启用与 Java2 Enterprise Edition (J2EE) 平台约定兼容的 JNDI InitialContext。

于 2018-07-25T12:05:41.797 回答
0

我也有这个问题,但是对于 Tomee 来说是新手,我不知道有一个简单的解决方案。当我将我的 web 应用程序部署到 webapps 文件夹时,该应用程序运行良好,但是当我将它部署到服务文件夹时,我得到了同样的中止。问题是文件夹名称与战争名称不匹配(减去 .war)。一旦我解决了这个问题,该应用程序就可以正常工作了。确保战争名称、文件夹名称和服务名称相同。此问题会产生几个不同的错误,包括 Context is read only 和 Error merging Java EE JNDI entries。

于 2017-12-08T20:35:35.303 回答
0

当我发现我正在关闭 environmentContext 对象时我解决了这个问题例如:

Context context=new InitialContext();
Context environmentContext=(Context) context.lookup("java:comp/env");

我的代码是:

environmentContext.close();

从 environmentContext 中删除关闭功能后,问题被卖给了我;

于 2015-11-21T19:30:26.457 回答