2009-07-06 22 views
8

Estoy usando Spring para manejar llamadas RMI a algún servidor remoto. Es sencillo de construir un contexto de aplicación y obtener el grano para invocaciones remotas desde el cliente de:Pasando propiedades a un contexto Spring

ApplicationContext context = new ApplicationContext("classpath:context.xml"); 

MyService myService = (MyService) context.getBean("myService "); 

Sin embargo no ver una forma sencilla de pasar propiedades en la configuración. Por ejemplo, si deseo determinar el nombre de host para el servidor remoto en tiempo de ejecución dentro del cliente.

Me ideal sería tener una entrada en el contexto de primavera como esta:

<bean id="myService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> 
    <property name="serviceUrl" value="rmi://${webServer.host}:80/MyService"/> 
    <property name="serviceInterface" value="com.foo.MyService"/> 
</bean> 

y pasar las propiedades con el contexto desde el cliente como parámetro.

Puedo usar PropertyPlaceholderConfigurer en el contexto para sustituir estas propiedades, pero hasta donde puedo decir esto solo funciona para las propiedades leídas de un archivo.

Tengo una implementación que aborda esto (agregada como una respuesta) pero estoy buscando una implementación estándar de Spring para evitar hacerla mía. ¿Hay otro configurador de Spring (o cualquier otra cosa) para ayudar a inicializar la configuración o me conviene más mirar la configuración de java para lograr esto?

+0

¿Dónde más se puede almacenar sus propiedades? –

+0

el cliente puede conectarse a cualquier servidor, p. el usuario puede escribir el nombre de host en un campo de texto. Por lo tanto, no está determinado en el momento de la compilación. –

Respuesta

1

actualización:

Sobre la base de la actualización pregunta, mi sugerencia es:

  1. Crear un grano ServiceResolver que se ocupa de todo lo que necesita para manejar base a la entrada del cliente;
  2. Declara este bean como una dependencia de los servicios relevantes;
  3. En tiempo de ejecución, puede actualizar/usar este bean como mejor le parezca.

El ServiceResolver puede entonces, ya sea en el init-method o en cada invocación determinar los valores para volver a la cliente, basado en, por ejemplo, Búsquedas JNDI o variables del entorno.

Pero antes de hacer eso, es posible que desee echar un vistazo a la configuration options disponible. Puede:

  • agregar archivos de propiedad que no tienen que estar presentes en tiempo de compilación;
  • buscar valores desde JNDI;
  • obtener valores de System.properties.

Si necesita buscar las propiedades de una ubicación personalizada, echar un vistazo a org.springframework.beans.factory.config.BeanFactoryPostProcessor y cómo se implementa la org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.

La idea básica es que obtenga los granos con las propiedades 'en bruto', p. ${jdbcDriverClassName} y luego puede resolverlos y reemplazarlos con los valores deseados.

+0

Gracias a la forma en que lo hace mi implementación actual, actualizaré mi pregunta para reflejar eso. Tenía la esperanza de que haya una implementación estándar de Spring para esto, así puedo evitar rodar la mía. –

1

PropertyPlaceholderConfigurer puede obtener propiedades de un archivo, eso es cierto, pero si no puede encontrarlas, vuelve a utilizar las propiedades del sistema.Esto suena como una opción viable para su aplicación cliente, simplemente pase la propiedad del sistema usando -D cuando ejecute el cliente.

Desde el javadoc

A configurer también comprobará contra propiedades del sistema (por ejemplo "user.dir") si no puede resolver un marcador de posición con cualquiera de las propiedades especificadas. Este se puede personalizar a través de "systemPropertiesMode".

2

Mi solución existente implica la definición de un nuevo MapAwareApplicationContext que toma un mapa como un argumento de constructor adicional.

public MapAwareApplicationContext(final URL[] configURLs, 
    final String[] newConfigLocations, 
    final Map<String, String> additionalProperties) { 
    super(null); 

    //standard constructor content here 

    this.map = new HashMap<String, String>(additionalProperties); 

    refresh(); 
} 

Se anula postProcessBeanFactory() para añadir en una MapAwareProcessor:

protected void postProcessBeanFactory(
    final ConfigurableListableBeanFactory beanFactory) { 
    beanFactory.addBeanPostProcessor(new MapAwareProcessor(this.map)); 
    beanFactory.ignoreDependencyInterface(MapAware.class); 
} 

El MapAwareProcessor implementa postProcessBeforeInitialization() para inyectar el mapa en cualquier tipo que implementa la interfaz MapAware:

public Object postProcessBeforeInitialization(final Object bean, 
     final String beanName) { 
    if (this.map != null && bean instanceof MapAware) { 
     ((MapAware) bean).setMap(this.map); 
    } 

    return bean; 
} 

Luego agrego un nuevo bean a mi config para declarar un MapAwarePropertyPlaceholderConfigurer:

<bean id="propertyConfigurer" 
    class="com.hsbc.r2ds.spring.MapAwarePropertyPlaceholderConfigurer"/> 

El configurador implementa MapAware, por lo que se inyectará con el Mapa como se indicó anteriormente. A continuación, implementa resolvePlaceholder() para resolver las propiedades del mapa, o delegar en el configurador de los padres:

protected String resolvePlaceholder(final String placeholder, 
     final Properties props, final int systemPropertiesMode) { 
    String propVal = null; 
    if (this.map != null) { 
     propVal = this.map.get(placeholder); 
    } 
    if (propVal == null) { 
     propVal = super.resolvePlaceholder(placeholder, props); 
    } 
    return propVal; 
} 
+1

Buen señor, esa es una solución complicada a un problema simple ... – skaffman

+0

Ese es mi punto, parece algo que debería lograrse sin demasiado esfuerzo, ciertamente menos esfuerzo que este –

+0

O podría usar BeanFactoryPostProcessor: http://springindepth.com/book/in-depth-ioc-bean- post-processors-and-beanFactory-post-processors.html – Talijanac

0

Crear una instancia RmiProxyFactoryBean y configurar la propiedad serviceUrl directamente en el código:

String serverHost = "www.example.com"; 

RmiProxyFactoryBean factory = new RmiProxyFactoryBean(); 
factory.setServiceUrl("rmi://" + serverHost + ":80/MyService"); 
factory.setServiceInterface(MyService.class); 
try { 
    factory.afterPropertiesSet(); 
} catch (Exception e) { 
    throw new RuntimeException(
      "Problem initializing myService factory", e); 
} 
MyService myService = (MyService) factory.getObject(); 
13

Ver http://forum.springsource.org/showthread.php?t=71815

TestClass.java

package com.spring.ioc; 

public class TestClass { 

    private String first; 
    private String second; 

    public String getFirst() { 
     return first; 
    } 

    public void setFirst(String first) { 
     this.first = first; 
    } 

    public String getSecond() { 
     return second; 
    } 

    public void setSecond(String second) { 
     this.second = second; 
    } 
} 

SpringStart.java

package com.spring; 

import java.util.Properties; 

import com.spring.ioc.TestClass; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 

public class SpringStart { 
    public static void main(String[] args) throws Exception { 
    PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer(); 
    Properties properties = new Properties(); 
    properties.setProperty("first.prop", "first value"); 
    properties.setProperty("second.prop", "second value"); 
    configurer.setProperties(properties); 

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); 
    context.addBeanFactoryPostProcessor(configurer); 

    context.setConfigLocation("spring-config.xml"); 
    context.refresh(); 

    TestClass testClass = (TestClass)context.getBean("testBean"); 
    System.out.println(testClass.getFirst()); 
    System.out.println(testClass.getSecond()); 
    } 
} 

spring-config.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation=" 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> 

    <bean id="testBean" class="com.spring.ioc.TestClass"> 
     <property name="first" value="${first.prop}"/> 
     <property name="second" value="${second.prop}"/> 
    </bean> 

</beans> 

Salida:

first value 
second value 
Cuestiones relacionadas