Подтвердить что ты не робот

Исходный текст в автономной программе Java

Я использую JNDI для создания пула соединений tomcat. Он отлично работает в веб-приложении. Я считаю, что исходный текст предоставлен сервером tomcat.

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

4b9b3361

Ответ 1

Вы также можете создать свой собственный контекст.

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

Для получения дополнительной информации см. Запуск локальных компонентов, использующих источники данных сервера приложений.


new ОБНОВЛЕНИЕ

Вы можете использовать класс org.springframework.mock.jndi.SimpleNamingContextBuilder of Spring. например:

  • Настроить:

    SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
    builder.bind("jdbc/Oracle", ods);
    builder.activate();
    
  • Использование:

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

Ответ 2

Вот пример, адаптированный из принятого ответа, но выполняющий все inline, чтобы избежать создания дополнительных классов.

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

Ответ 3

Нет прямого способа использования Контекста Tomcat Factory, см. здесь для получения дополнительной документации по альтернативам. Но я рекомендую вам попробовать запустить реестр за пределами 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-провайдер. Этот question кажется очень похожим.

Ответ 4

Tomcat предоставляет реализации контекста и DataSource, которые работают с классом InitialContext. При запуске Tomcat свойство Context.INITIAL_CONTEXT_FACTORY устанавливается так, чтобы оно указывало на реализацию Tomcat. Когда вы не используете Tomcat, у вас нет этой возможности... вам нужно использовать стороннюю библиотеку, например c3p0 для объединения пулов.

Ответ 5

Вы можете создать начальный контекст, используя код удара.

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

если вы хотите создать собственный начальный контекст, вы можете расширить класс javax.naming.InitailContext

Ответ 6

Вы можете создать свой собственный Context, подклассифицируя javax.naming.InitialContext и реализуя только небольшое подмножество методов, обычно это методы bind и lookup.

Затем вы можете создать свой источник данных и связать его с вашим начальным контекстом с определенным ключом. После этого вы готовы пойти и запросить из любого места свой JNDI-контекст в вашей автономной Java-программе.

Это код, который вы можете использовать для создания своего собственного контекста:

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