2011-05-12 20 views
8

Tenemos una aplicación de resorte independiente y necesitamos poner jdbc datasource en jndi. (usamos el treecache de jboss y necesitamos el origen de datos para estar en el jndi).cómo poner (atar) objeto a jndi en primavera declarativamente?

Algunos de Google encontraron la mayoría de todos los ejemplos de jndi-lookup con spring, donde un objeto ya está en jndi (por tomcat o servidor de aplicaciones, etc.), pero necesitamos lo contrario: tengo un datasource simple Spring Bean, que doy a otros servicios, pero no puedo inyectarlo a TreeCache, porque solo lo necesita de jndi.

Encontrado org.springframework.jndi.JndiTemplate, que puede ser declarado como frijol, por ejemplo .:

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

pero no encontrado cómo enlazar con ella que no sea en código Java: fsJndiTemplate.bind(name, obj) de init-método de algún otro bean. ¿Hay alguna forma de hacerlo declarativamente?

+0

http://stackoverflow.com/questions/4414115/spring-as-a-jndi-provider – Polaris878

Respuesta

7

Tu puede crear un JndiExporter que utiliza un JndiTemplate para unir un mapa de objeto con un nombre:

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

Su JndiExporter tienen que implementa BeanFactoryAware para recuperar el grano de la primavera con el BeanFactory inyectado.

Ésta es una de las posibles pueden :)

+0

sí, ya lo hizo, parece que funciona bien) Pero sólo un poco de curiosidad por qué no hay tal ayudante en la primavera, solo múltiples formas de búsqueda de jndi. – yetanothercoder

2

Hola No existe una norma o mejores prácticas de enfoque tipo para este problema. Habrá venido con su propio enfoque. A continuación está el otro enfoque que puede encargarse de su problema.

  1. Hacer javax.naming.InitialContext un grano de primavera (digamos initialContext). Asegúrese de pasarle un mapa apropiado de propiedades iniciales según sea necesario.

  2. Ahora crea otro bean, di JndiBinder. Inyecte el frijol mencionado n. ° 1 arriba en este frijol. Este bean tomará un mapa de jndi-nombres y objetos correspondientes. Para su caso, el objeto será fuente de datos, ya disponible en el contexto de primavera.

  3. En la definición de bean JndiBinder, escriba un método init que llamaría bind menthod de initialContext para todas las entradas en el mapa (de jndi-names y objetos correspondientes). De esta forma, todas las entradas en el mapa suministradas están vinculadas al árbol JNDI.

+0

Esto es esencialmente lo que hice en mi solución a este problema: http://stackoverflow.com/questions/4414115/spring-as-a-jndi-provider – Polaris878

12

Gracias por las preguntas. Escribí una variante de la solución de Treydone y pensé que podría ser útil disponer de código real aquí (ya que es bastante corto):

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

} 

Tenga en cuenta que he implementado InitializingBean en lugar de BeanFactoryAware. Esto permite una configuración (con referencias) así:

<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> 
5

Comprendo que esto es una vieja pregunta, pero hay una manera de hacer esto sin código personalizado. Es bastante detallado, pero 100% declarativo.

<!-- 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> 

El MethodInvokingFactoryBean también se puede utilizar para establecer las propiedades del sistema (which comes in handy when using Atomikos), siempre y cuando el grano que lee las propiedades del sistema depends-on que 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"/> 
0

Si el código se está ejecutando fuera de un contenedor de servlets, p. en una prueba unitaria, el contexto JNDI necesita ser emulado. De lo contrario, obtendrás el temido error "Necesito especificar el nombre de clase en el entorno ...".

SimpleNamingContextBuilder es más adecuado para que, de 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; 
} 

No pase por alto la "contextBuilder.activate();" línea.

Cuestiones relacionadas