尝试使用 Simple-JNDI 时出错

Error when trying to use Simple-JNDI

出于单元测试的目的,我尝试设置 JNDI 以在不使用 Tomcat 的情况下连接到 HSQLDB。为此,我使用 Simple-JNDI and following this website

所以首先我创建了一个 class 来初始化 JNDI 数据源:

import org.hsqldb.jdbc.JDBCDataSource;    
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JndiDataSource {
    public void Initialize() throws NamingException {
        // Create initial context
        System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.osjava.sj.MemoryContextFactory");
        System.setProperty("org.osjava.sj.jndi.shared", "true");
        InitialContext ic = new InitialContext();

        ic.createSubcontext("java:/comp/env/jdbc");

        // Construct DataSource
        JDBCDataSource ds = new JDBCDataSource();
        ds.setDatabase("jdbc:hsqldb:hsql://localhost/xdb");
        ds.setUser("SA");
        ds.setPassword("");

        // Put datasource in JNDI context
        ic.bind("java:/comp/env/jdbc/myDS", ds);
    }
}

然后在单元测试中我调用 Initialize() 并试图查找数据源。

import org.junit.jupiter.api.Test;    
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class JndiDataSourceTest {
    @Test
    public void testInitialize() throws NamingException {
        JndiDataSource jds = new JndiDataSource();
        jds.Initialize();

        InitialContext ic = new InitialContext();
        DataSource ds = (DataSource)ic.lookup("java:/comp/env/jdbc/myDS");
    }
}

不幸的是,当我尝试调试这个单元测试时,它在查找时失败了,(DataSource)ic.lookup("java:/comp/env/jdbc/myDS");调试器说,

javax.naming.NameNotFoundException: java:/comp/env/jdbc/myDS

所以问题是,我做错了什么?

可能是一个简单的错字 - 恕我直言,应该是 org.osjava.sj.memory.MemoryContextFactory

Simple-JNDI 0.18.1 之前的问题是 org.osjava.sj.MemoryContextFactory 没有考虑系统属性。因此每次调用

new InitialContext()

一个新的 MemoryContext 被初始化,它不与之前初始化的 MemoryContext 共享任何内容。

我用 0.18.2 改变了这个行为。到那时有两个解决方案。

第一个:

将 jndi.properties 放入包含以下内容的类路径中:

java.naming.factory.initial = org.osjava.sj.MemoryContextFactory
org.osjava.sj.jndi.shared = true

因此您可以免除系统属性。

第二

一种更容易出错的方法。使用采用环境配置的构造函数:

InitialContext(Hashtable<?, ?> environment)

每次实例化一个新的 InitialContext 时,您必须为构造函数提供此环境:

    System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.osjava.sj.MemoryContextFactory");

    Hashtable env = new Hashtable();
    env.put("org.osjava.sj.jndi.shared", "true");

    InitialContext ic = new InitialContext(env);

    ic.createSubcontext("java:/comp/env/jdbc");

    JDBCDataSource ds = new JDBCDataSource();
    ds.setDatabase("jdbc:hsqldb:hsql://localhost/xdb");
    ds.setUser("SA");
    ds.setPassword("");

    ic.bind("java:/comp/env/jdbc/myDS", ds);

    // And elsewhere

    Hashtable env = new Hashtable();
    env.put("org.osjava.sj.jndi.shared", "true");
    InitialContext ic2 = new InitialContext(env);
    DataSource dataSource = (DataSource) ic2.lookup("java:/comp/env/jdbc/myDS");
    assertNotNull(dataSource);

我也建议设置

jndi.syntax.direction = left_to_right
jndi.syntax.separator = /

Simple-JNDI > 0.11.4.1 有很多优点。参见 here