как поставить (привязать) объект к jndi весной декларативно? - PullRequest
9 голосов
/ 12 мая 2011

У нас есть простое автономное весеннее приложение, и нам нужно поместить источник данных jdbc в jndi. (мы используем jboss treecache и ему нужен источник данных, чтобы быть в jndi).

Некоторые из поисковиков нашли больше всего примеров jndi-lookup с помощью Spring, где объект уже помещен в jndi (через tomcat или сервер приложений и т. Д.), Но нам нужно иначе: у меня есть простой источник данных bean-компонента Spring, который я добавляю в другие службы, но я не могу внедрить его в TreeCache, потому что он нужен только из jndi.

Найдено org.springframework.jndi.JndiTemplate, которое может быть объявлено как bean-компонент, например ::10000

<bean id="fsJndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">com.sun.jndi.fscontext.RefFSContextFactory</prop>
            <prop key="java.naming.provider.url">file:///c:\windows\temp</prop>
        </props>
    </property>
</bean>

но не нашел, как связать с ним, кроме как в Java-коде: fsJndiTemplate.bind(name, obj) из init-метода какого-то другого компонента. Есть ли способ сделать это декларативно?

Ответы [ 5 ]

13 голосов
/ 09 июля 2012

Спасибо за вопросы.Я написал вариант решения Treydone и подумал, что может быть полезно иметь здесь реальный код (поскольку он довольно короткий):

public class JndiExporter implements InitializingBean {

    private final JndiTemplate template = new JndiTemplate();

    private Map<String, Object> jndiMapping = null;

    @Override
    public void afterPropertiesSet() throws Exception {
            for(Entry<String, Object> addToJndi: jndiMapping.entrySet()){
                    template.bind(addToJndi.getKey(), addToJndi.getValue());
            }
    }

    public void setJndiMapping(Map<String, Object> jndiMapping) {
            this.jndiMapping = jndiMapping;
    }

}

Обратите внимание, что я реализовал InitializingBean вместо BeanFactoryAware.Это позволяет настроить конфигурацию (со ссылками) следующим образом:

<bean id="jndiExporter" class="com.ra.web.util.JndiExporter">
    <property name="jndiMapping">
        <map>
            <entry key="bean1" value-ref="other_spring_bean_id" />
            <entry key="bean2" value="literal_value" />
        </map>
    </property>
</bean>
7 голосов
/ 12 мая 2011

Вы можете создать JndiExporter, который использует JndiTemplate для привязки карты объекта с именем:

<bean id="jndiExporter" class="org.xxx.JndiExporter">
    <property name="jndiTemplate" ref="jndiTemplate">
    <property name="objects">
          <map>
            <entry key="name1" value="bean1"/>
            <entry key="name2" value="bean2"/>
            <entry key="name3" value="bean3"/>
            <entry key="name4" value="bean4"/>
          </map>
    </property>
</bean>

В вашем JndiExporter должен быть реализован BeanFactoryAware для получения пружинного компонента с введенным BeanFactory.

Это один из возможных мая:)

6 голосов
/ 27 июля 2013

Я понимаю, что это старый вопрос, но есть способ сделать это без специального кода.Это довольно многословно, но на 100% декларативно.

<!-- inside container, use JndiTemplate -->
<bean id="jndiBinder" class="org.springframework.jndi.JndiTemplate"/>
<!-- outside container (e.g. for tests), use SimpleNamingContextBuilder -->
<!-- <bean id="jndiBinder" class="org.springframework.mock.jndi.SimpleNamingContextBuilder" factory-method="emptyActivatedContextBuilder"/> -->

<!-- use MethodInvokingFactoryBean to call 'bind' on 'jndiBinder' -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="jndiBinder"/>
    <property name="targetMethod" value="bind"/>
    <property name="arguments">
        <array>
            <value type="java.lang.String">java:comp/UserTransaction</value>
            <ref bean="atomikosUserTransaction"/>
        </array>
    </property>
</bean>

<!-- define as many bindings as you need -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="jndiBinder"/>
    <property name="targetMethod" value="bind"/>
    <property name="arguments">
        <array>
            <value type="java.lang.String">another/jndi/name</value>
            <value>literal_value</value>
        </array>
    </property>
</bean>

MethodInvokingFactoryBean также можно использовать для установки системных свойств (, что удобно при использовании Atomikos ), если толькоbean-компонент, который читает системные свойства depends-on, что MethodInvokingFactoryBean.

<bean id="atomikosSystemProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <bean class="java.lang.System" factory-method="getProperties"/>
    </property>
    <property name="targetMethod" value="putAll"/>
    <property name="arguments" ref="atomikosJtaProps"/>
</bean>
<bean id="atomikosJtaProps" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="properties">
        <props>
            <prop key="com.atomikos.icatch.no_file">true</prop>
            <prop key="com.atomikos.icatch.hide_init_file_path">true</prop>
            <prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactory</prop>
            <prop key="com.atomikos.icatch.log_base_dir">/opt/txlogs</prop>
        </props>
    </property>
</bean>
<bean id="atomikosUserTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp" init-method="init" destroy-method="shutdownForce" depends-on="atomikosSystemProps"/>
3 голосов
/ 12 мая 2011

Привет. Для этой проблемы не существует стандартного или оптимального подхода.Вы придете с вашим собственным подходом.Ниже приведен еще один подход, который может решить вашу проблему.

  1. Сделайте javax.naming.InitialContext пружинным компонентом (скажем, initialContext).Убедитесь, что вы передали ему соответствующую карту исходных свойств, как требуется.

  2. Теперь создайте еще один компонент, скажем, JndiBinder.Введите боб, упомянутый выше в этом бине.Этот бин возьмет карту jndi-имён и соответствующих объектов.В вашем случае, объект будет источником данных, уже доступным в контексте весны.

  3. В определении компонента JndiBinder напишите метод init, который будет вызывать метод bind menthod initialContext для всех записей.на карте (из jndi-имен и соответствующих объектов).Таким образом, все записи в предоставленной карте привязаны к дереву JNDI.

0 голосов
/ 04 января 2015

Если код выполняется вне контейнера сервлета, например, в модульном тесте контекст JNDI должен быть эмулирован. В противном случае вы получите страшную ошибку «Необходимо указать имя класса в среде ...».

SimpleNamingContextBuilder лучше подходит для этого, чем JndiTemplate:

public class JndiExporter implements InitializingBean {

private final SimpleNamingContextBuilder contextBuilder = new SimpleNamingContextBuilder();

private Map<String, Object> jndiMapping = null;

@Override
public void afterPropertiesSet() throws Exception {
    for (Entry<String, Object> addToJndi : jndiMapping.entrySet()) {
        contextBuilder.bind(addToJndi.getKey(), addToJndi.getValue());
    }

    contextBuilder.activate();
}

public void setJndiMapping(Map<String, Object> jndiMapping) {
    this.jndiMapping = jndiMapping;
}

Не пропустите "contextBuilder.activate ();" линия.

...