Java 上下文是只读的

Java 上下文是只读的,java,spring,tomcat,servlets,jndi,Java,Spring,Tomcat,Servlets,Jndi,Helo masters,我必须动态创建一个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-

Helo masters,我必须动态创建一个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>
这里有一个错误:

[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)
我可以将上下文的只读属性设置为“true”吗?谢谢!:)


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

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

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


回到您的问题,我认为tomcat在运行时修改JNDI方面有严格的规则。换句话说,您不能从上下文中重新绑定或删除jndi。如果您浏览tomcat规范,您可能会看到一些关于jndi查找的内容,但没有重新绑定。

来自EE 6平台规范(JSR 316)第EE.5.3.4节:

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


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

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

Context context=new InitialContext();
Context environmentContext=(Context) context.lookup("java:comp/env");
我的代码是:

environmentContext.close();

从Environment中删除close函数后,上下文问题为我解决了

您需要创建一个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();
    }
}
受保护的void使jndicontextwriteable(ServletContextEvent sce){
试一试{
类contextAccessControllerClass=sce.getClass().getClassLoader().loadClass(“org.apache.naming.ContextAccessController”);
Field readOnlyContextsField=contextAccessControllerClass.getDeclaredField(“readOnlyContexts”);
readOnlyContextsField.setAccessible(true);
Hashtable readOnlyContexts=(Hashtable)readOnlyContextsField.get(null);
字符串上下文=null;
for(对象键:ReadOnlyContext.keySet()){
字符串keyString=key+“”;
if(keyString.endsWith(sce.getServletContext().getContextPath()){
上下文=键串;
}
}
readonlyContext.remove(上下文);
}捕获(例外情况除外){
例如printStackTrace();
}
}

我也有这个问题,但作为我的新手,我不知道有一个简单的解决方案。当我将我的web应用部署到webapps文件夹时,该应用运行良好,但当我将其部署到服务文件夹时,我得到了相同的中止。问题是文件夹名称与war名称(减去.war)不匹配。一旦我解决了这个问题,这个应用程序运行得很好。确保war名称、文件夹名称和服务名称相同。此问题会产生几个不同的错误,包括上下文为只读和合并Java EE JNDI条目时出错。

我通过在my Context.xml中设置
useNaming=“false”
解决了此问题

:

useNaming:设置为true(默认值),使Catalina为此web应用程序启用与Java2 Enterprise Edition(J2EE)平台约定兼容的JNDI InitialContext


因为有些模块引用与jndi的连接。由于安全问题,他们不想在服务器中放置连接值(user、pass等),因为它是一个共享服务器。我需要在应用程序内部定义一个jndi数据源,你知道没有听众的另一种方式吗?不需要dinamically@rubenGL但是他们不能检查context.xml文件来获取这些值吗?context.xml是一个服务器文件,他们不想将连接值放在服务器中。有些模块引用与jndi的连接。由于安全问题,他们不想在服务器中放置连接值(user、pass等),因为它是共享服务器。我需要在应用程序中定义一个jndi数据源,在内部,你知道没有侦听器的另一种方法吗?不需要是DINAMICALL+1 user2021142,jndi意味着将源代码与连接配置解耦。服务器上的JNDI配置可以仅限于管理员用户,如果这是出于安全目的的话。此外,数据库连接可以启用SSL以避免任何恶意查找。由于OscarRyz,我记得在EE6中读到过,他们带来了java:global,它不是只读的。你知道吗?我以前没用过。
environmentContext.close();
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();
    }
}