如何在声明中将(绑定)对象放到jndi中?

时间:2011-05-12 07:35:10

标签: java spring configuration jndi

我们有一个普通的独立spring应用程序,我们需要将jdbc数据源放在jndi中。 (我们使用jboss treecache,它需要数据源在jndi中)。

一些谷歌搜索发现大多数使用spring的jndi-lookup示例,其中一个对象已经放入jndi(通过tomcat或应用程序服务器等),但我们还需要:我有一个普通的数据源Spring bean,我注入了其他服务,但我无法将其注入TreeCache,因为它只需要来自jndi。

找到org.springframework.jndi.JndiTemplate,可以声明为bean,例如:

<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)来自其他bean的init-method。 有没有办法以声明的方式做到这一点?

5 个答案:

答案 0 :(得分:12)

感谢您的提问。我写了一个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>

答案 1 :(得分:7)

您可以创建一个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检索spring bean。

这是可能的一种:)

答案 2 :(得分:5)

我意识到这是一个老问题,但有一种方法可以在没有自定义代码的情况下执行此操作。它相当冗长,但是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也可用于设置系统属性(which comes in handy when using Atomikos),只要读取系统属性depends-on的{​​{1}}。

MethodInvokingFactoryBean

答案 3 :(得分:3)

您好    此问题没有标准或最佳实践类型方法。您将拥有自己的方法。以下是另一种可以解决您问题的方法。

  1. 使javax.naming.InitialContext成为一个spring bean(比如initialContext)。确保根据需要将初始属性的适当地图传递给它。

  2. 现在创建另一个bean说JndiBinder。在这个bean中注入上面提到的#1 bean。这个bean将获取jndi-names和相应对象的映射。对于您的情况,该对象将是数据源,已在spring上下文中提供。

  3. 在JndiBinder bean定义中,编写一个init方法,该方法将为地图中的所有条目(jndi-names和相应对象)调用initialContext的bind menthod。这样,提供的映射中的所有条目都绑定到JNDI树。

答案 4 :(得分:0)

如果代码在Servlet容器外执行,例如在单元测试中,需要模拟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();”线。