独立Java程序中的Initialcontext

时间:2013-12-03 19:03:33

标签: java java-ee tomcat jndi connection-pooling

我正在使用JNDI创建tomcat连接池。它在Web应用程序中运行良好。我相信InitialContext是由tomcat服务器提供的。

Context initContext  = new InitialContext();
Context envContext  = (Context)initContext.lookup("java:/comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/testdb");

但是当我尝试从独立的Java程序调用相同的实用程序时,initContext对象为null。如何显式提供Context对象期望的所有必要属性。

  

错误:javax.naming.NoInitialContextException:需要指定类   环境或系统属性中的名称,或applet参数,或   在应用程序资源文件中:java.naming.factory.initial

6 个答案:

答案 0 :(得分:22)

这是一个根据已接受的答案改编的示例,但是为了避免创建额外的类而内联所有内容。

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();
    }
}

答案 1 :(得分:8)

您还可以创建自己的自定义上下文。

LocalContext ctx = LocalContextFactory.createLocalContext();
ctx.addDataSource("jdbc/testdb", driverName, url, usr, pwd);

有关详细信息,请参阅Running Beans Locally that use Application Server Data Sources


new 更新

您可以使用Spring的org.springframework.mock.jndi.SimpleNamingContextBuilder类。 e.g:

  • 设定:

    SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
    builder.bind("jdbc/Oracle", ods);
    builder.activate();
    
  • 使用:

    DataSource ds = InitialContext.doLookup("jdbc/Oracle");
    

答案 2 :(得分:1)

没有一种方法可以直接使用Tomcat Context Factory,请参阅here以获取有关替代方案的更多文档。但我建议您尝试在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,然后两个set都将使用相同的JNDI提供程序。 question似乎非常相似。

答案 3 :(得分:0)

Tomcat提供了Context&amp;与InitialContext类一起使用的DataSource实现。运行Tomcat时,Context.INITIAL_CONTEXT_FACTORY属性设置为指向Tomcat的实现。当没有运行Tomcat时,你没有这种能力......你需要使用像c3p0这样的第三方库来连接池。

答案 4 :(得分:0)

您可以使用打击代码创建初始上下文。

InitialContext ic = new InitialContext();
    // Retrieve the Home interface using JNDI lookup
    Object helloObject = ic.lookup("java:comp/env/ejb/HelloBean");

如果要创建自定义初始上下文,可以扩展javax.naming.InitailContext类

答案 5 :(得分:0)

您可以通过对Context进行子类化并仅实现一小部分方法来创建自己的javax.naming.InitialContext,通常是bindlookup方法。

然后,您可以创建数据源,并将其绑定到特定上下文的初始上下文。之后,您就可以开始在独立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);

然后,您可以选择任何一个来初始化数据源:

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);

在代码的其他地方,您可以通过从JNDI上下文中检索现有数据源来使用它:

InitialContext ic2 = new InitialContext();
DataSource ds = (DataSource) ic2.lookup(jndiPath);
assertNotNull(ds);
Connection conn = ds.getConnection();
assertNotNull(conn);
conn.close();