尝试使用 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。
出于单元测试的目的,我尝试设置 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。