独立Java程序中的Initialcontext
我正在使用JNDI创建连接池。它在web应用程序中非常有效。我相信InitialContext是由tomcat服务器提供的独立Java程序中的Initialcontext,java,jndi,Java,Jndi,我正在使用JNDI创建连接池。它在web应用程序中非常有效。我相信InitialContext是由tomcat服务器提供的 Context initContext = new InitialContext(); Context envContext = (Context)initContext.lookup("java:/comp/env"); dataSource = (DataSource)envContext.lookup("jdbc/testdb&quo
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/testdb");
但是当我试图从独立Java程序调用同一个实用程序时,initContext对象为null。如何显式地提供上下文对象所期望的所有必要属性
错误:javax.naming.NoInitialContextException:需要指定类
环境或系统属性中的名称,或作为小程序参数,或
在应用程序资源文件中:java.naming.factory.initial
Tomcat提供了使用InitialContext类的上下文和数据源实现。运行Tomcat时,Context.INITIAL\u Context\u工厂属性设置为指向Tomcat的实现。不运行Tomcat时,您没有此能力。。。您需要使用像c3p0这样的第三方库来进行连接池。没有直接使用Tomcat上下文工厂的方法,请参阅更多关于替代方法的文档。但我建议您尝试在Tomcat之外运行注册表
// select the registry context factory for creating a context
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
// specify where that factory is running.
env.put(Context.PROVIDER_URL, "rmi://server:1099");
// create an initial context that accesses the registry
Context ctx = new InitialContext(env);
您可以将Tomcat中的代码更改为也使用此外部RegistryContext,然后两个集合将使用相同的JNDI提供程序。这似乎非常相似。您还可以创建自己的自定义上下文
LocalContext ctx = LocalContextFactory.createLocalContext();
ctx.addDataSource("jdbc/testdb", driverName, url, usr, pwd);
有关更多详细信息,请参阅
更新 您可以使用Spring类。e、 g:
- 设置:
- 使用:
public static void main(String[] args) {
setupInitialContext();
//do something that looks up a datasource
}
private static void setupInitialContext() {
try {
NamingManager.setInitialContextFactoryBuilder(new InitialContextFactoryBuilder() {
@Override
public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment) throws NamingException {
return new InitialContextFactory() {
@Override
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
return new InitialContext(){
private Hashtable<String, DataSource> dataSources = new Hashtable<>();
@Override
public Object lookup(String name) throws NamingException {
if (dataSources.isEmpty()) { //init datasources
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
ds.setURL("jdbc:mysql://localhost:3306/mydb");
ds.setUser("mydbuser");
ds.setPassword("mydbpass");
dataSources.put("jdbc/mydbname", ds);
//add more datasources to the list as necessary
}
if (dataSources.containsKey(name)) {
return dataSources.get(name);
}
throw new NamingException("Unable to find datasource: "+name);
}
};
}
};
}
});
}
catch (NamingException ne) {
ne.printStackTrace();
}
}
publicstaticvoidmain(字符串[]args){
setupInitialContext();
//执行查找数据源的操作
}
私有静态void setupInitialContext(){
试一试{
NamingManager.setInitialContextFactoryBuilder(新的InitialContextFactoryBuilder(){
@凌驾
公共InitialContextFactory createInitialContextFactory(哈希表环境)引发NamingException{
返回新的InitialContextFactory(){
@凌驾
公共上下文getInitialContext(哈希表环境)引发NamingException{
返回新的InitialContext(){
私有哈希表数据源=新哈希表();
@凌驾
公共对象查找(字符串名称)引发NamingException{
if(dataSources.isEmpty()){//init dataSources
MysqlConnectionPoolDataSource ds=新的MysqlConnectionPoolDataSource();
ds.setURL(“jdbc:mysql://localhost:3306/mydb");
ds.setUser(“mydbuser”);
设置密码(“mydbpass”);
dataSources.put(“jdbc/mydbname”,ds);
//根据需要向列表中添加更多数据源
}
if(dataSources.containsKey(名称)){
返回dataSources.get(name);
}
抛出新的NamingException(“找不到数据源:“+name”);
}
};
}
};
}
});
}
捕获(纳明异常){
ne.printStackTrace();
}
}
您可以使用blow代码创建初始上下文
InitialContext ic = new InitialContext();
// Retrieve the Home interface using JNDI lookup
Object helloObject = ic.lookup("java:comp/env/ejb/HelloBean");
如果您想创建自定义初始上下文,可以扩展javax.naming.InitailContext类您可以通过对
javax.naming.InitialContext
进行子分类并只实现一小部分方法(通常是bind
和lookup
方法)来创建自己的上下文
然后,您可以创建数据源,并将其绑定到特定键的初始上下文。在此之后,您就可以在独立Java程序中的任何地方查询JNDI上下文了
以下代码可用于创建自己的上下文:
InitialContext initialContext = new InitialContext() {
private Map<String, Object> table = new HashMap<>();
public void bind(String key, Object value) {
table.put(key, value);
}
public Object lookup(String key) throws NamingException {
return table.get(key);
}
};
// Activate the initial context
NamingManager.setInitialContextFactoryBuilder(environment -> environment1 -> initialContext);
在代码的其他地方,您可以通过从JNDI上下文检索现有数据源来使用它:
InitialContext ic2 = new InitialContext();
DataSource ds = (DataSource) ic2.lookup(jndiPath);
assertNotNull(ds);
Connection conn = ds.getConnection();
assertNotNull(conn);
conn.close();
祝贺最佳解决方案,简洁明了!这为我节省了数小时的时间,使我得以浏览Java的神秘API。非常感谢。这并不是在避免创建额外的类。这将创建几个匿名类。祝您在测试中好运。请注意,您链接的文章的最后一条评论指出解决方案存在缺陷:如果名称为null或未找到,则在查找过程中抛出StackOverflowException…非常好。设置“保存我的测试”。我操纵接口实现中使用的上下文,我没有使用spring或任何JavaEE技术。我仍然希望在服务器启动时使用本地上下文。
InitialContext initialContext = new InitialContext() {
private Map<String, Object> table = new HashMap<>();
public void bind(String key, Object value) {
table.put(key, value);
}
public Object lookup(String key) throws NamingException {
return table.get(key);
}
};
// Activate the initial context
NamingManager.setInitialContextFactoryBuilder(environment -> environment1 -> initialContext);
InitialContext ic = new InitialContext();
BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
bds.setUrl(url);
bds.setUsername(username);
bds.setPassword(password);
ic.bind(jndiPath, bds);
InitialContext ic2 = new InitialContext();
DataSource ds = (DataSource) ic2.lookup(jndiPath);
assertNotNull(ds);
Connection conn = ds.getConnection();
assertNotNull(conn);
conn.close();