独立 Java 程序中的初始上下文

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20359483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 01:21:55  来源:igfitidea点击:

Initialcontext in a standalone Java program

javajakarta-eetomcatjndiconnection-pooling

提问by Satish Jonnala

I'm using a JNDI for creating tomcat connection pool. It works great in a web application. I believe the InitialContext is provided by the tomcat server.

我正在使用 JNDI 来创建 tomcat 连接池。它在 Web 应用程序中工作得很好。我相信 InitialContext 是由 tomcat 服务器提供的。

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

But when I try to call the same utility from a standalone Java program, the initContext object is null. How can I explicitly provide all the necessary properties that Context object is expecting.

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

Error : javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial

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

采纳答案by Paul Vargas

You could also create your own custom context.

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

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

See Running Beans Locally that use Application Server Data Sourcesfor more details.

有关更多详细信息请参阅在本地运行使用应用程序服务器数据源的 Bean



newUPDATE

新的更新

You can use the class org.springframework.mock.jndi.SimpleNamingContextBuilderof Spring. e.g.:

您可以使用org.springframework.mock.jndi.SimpleNamingContextBuilderSpring类。例如:

  • Setup:

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

    DataSource ds = InitialContext.doLookup("jdbc/Oracle");
    
  • 设置:

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

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

回答by ClickerMonkey

Tomcat provides Context & DataSource implementations that work with the InitialContext class. When running Tomcat the Context.INITIAL_CONTEXT_FACTORY property is set to point to Tomcat's implementations. When not running Tomcat, you don't have this ability... you need to use a third-party-library like c3p0 for connection pooling.

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

回答by Elliott Frisch

There isn't a way to directly use the Tomcat Context Factory, see herefor a little more documentation on the alternatives. But I recommend you try running a registry outside of Tomcat...

没有办法直接使用 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);

You could change your code in Tomcat to also use this external RegistryContext and then both set(s) would be using the same JNDI provider. This questionseems very similar.

您可以更改 Tomcat 中的代码以也使用此外部 RegistryContext,然后两个集合将使用相同的 JNDI 提供程序。这个问题似乎非常相似。

回答by Scott Nelson

Here is an example adapted from the accepted answer but doing everything inline to avoid creating extra classes.

这是一个改编自已接受答案的示例,但内联执行所有操作以避免创建额外的类。

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

回答by faizan saifi

You can create an initial context using blow code.

您可以使用吹码创建初始上下文。

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

if you want create custom initial context, you can extends javax.naming.InitailContext class

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

回答by gil.fernandes

You can create your own Contextby sub-classing javax.naming.InitialContextand implementing only a small subset of methods, typically the bindand the lookupmethods.

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

Then you can create your data source and bind it to your initial context to a specific key. After this you are ready to go and query from any place your JNDI context in your stand-alone Java programme.

然后,您可以创建数据源并将其绑定到特定键的初始上下文。在此之后,您就可以从独立 Java 程序中的任何位置查询 JNDI 上下文了。

This is the code you can use to create your own context:

这是您可以用来创建自己的上下文的代码:

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

Then you can initialise your data source, whichever you choose:

然后您可以初始化您的数据源,无论您选择哪个:

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

And somewhere else in your code, you can use the existing data source by retrieving it from the JNDI context:

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

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