Pregunta

Estoy usando la primavera de manejar RMI llama 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:

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

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

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

Me ideal sería tener una entrada en el contexto de Primavera de esta manera:

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

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

Me puede utilizar un PropertyPlaceholderConfigurer en el contexto para sustituir a estas propiedades, pero por lo que yo puedo decir esto sólo funciona para leer las propiedades de un archivo.

Tengo una aplicación que soluciona este (añadida como una respuesta), pero estoy buscando una implementación estándar de la primavera para evitar rodar mi propia. ¿Hay otro configurador de primavera (o cualquier otra cosa) para ayudar a inicializar la configuración o estoy mejor mirando config java para lograr esto?

¿Fue útil?

Solución

Actualizar

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

  1. Crear un bean ServiceResolver que se ocupa de todo lo que necesita para manejar base a la entrada del cliente;
  2. Declarar este bean como una dependencia de los servicios pertinentes;
  3. En tiempo de ejecución, es posible actualizar / utilizar este bean sin embargo 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 o variables de entorno JNDI.

Pero antes de hacer eso, es posible que desee echar un vistazo a la opciones de configuración disponible. Puede:

  • añadir archivos de propiedades que no tiene que estar presente en tiempo de compilación;
  • buscar valores de JNDI;
  • obtener valores a partir de los 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 el org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.

La idea básica es que se obtiene de los granos con las propiedades 'en bruto', por ejemplo, ${jdbcDriverClassName} y luego se llega a resolverlos y reemplazarlos con los valores deseados.

Otros consejos

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

Mi solución existente consiste en definir un nuevo MapAwareApplicationContext que toma un mapa como un argumento del 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;
}

A continuación, añadir un nuevo bean a mi config para declarar una MapAwarePropertyPlaceholderConfigurer:

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

El configurador implementa MapAware, por lo que se inyecta con el mapa como 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;
}

PropertyPlaceholderConfigurer puede recuperar las propiedades de un archivo, eso es cierto, pero si no los encuentra, se vuelve a utilizar las propiedades del sistema. Esto suena como una opción viable para su aplicación cliente, sólo tiene que pasar la propiedad del sistema en el uso -D cuando se inicia el cliente.

En la javadoc

  

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

Crea 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();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top