Domanda

sto usando primavera per gestire RMI chiamate ad un server remoto. È semplice costruire un contesto applicativo ed ottenere il fagiolo di invocazioni remote dall'interno del client:

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

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

Comunque non vedo un modo semplice per passare le proprietà nella configurazione. Per esempio se voglio determinare il nome host per il server remoto in fase di esecuzione all'interno del client.

Mi piacerebbe idealmente avere una voce nel contesto primavera in questo modo:

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

e passare le proprietà del contesto da parte del cliente come parametro.

Posso usare un PropertyPlaceholderConfigurer nel contesto di sostituire tali proprietà, ma per quanto ne so questo funziona solo per le proprietà letti da un file.

Ho un'implementazione che risolve questo (aggiunto come una risposta), ma sto cercando un'implementazione primavera standard per evitare di rotazione mia. C'è un altro configurer Primavera (o qualsiasi altra cosa) per contribuire a inizializzare la configurazione o sto meglio guardando java config per raggiungere questo obiettivo?

È stato utile?

Soluzione

Aggiorna :

In base alla domanda di aggiornamento, il mio suggerimento è:

  1. Crea un fagiolo ServiceResolver che gestisce tutto ciò che è necessario gestire in base all'input cliente;
  2. Dichiarare questo fagiolo come dipendenza ai servizi competenti;
  3. In fase di runtime, è possibile aggiornare / utilizzare questo fagiolo però si vede in forma.

Il ServiceResolver possono poi, sia sul init-method o ad ogni invocazione determinare i valori per tornare al client, ad esempio sulla base di le ricerche o le variabili enviroment JNDI.

Ma prima di farlo, si potrebbe desiderare di dare un'occhiata al disponibili opzioni di configurazione. È possibile:

  • aggiungere file di proprietà, che non devono essere presenti al momento della compilazione;
  • cercare i valori da JNDI;
  • ottenere i valori dalle System.properties.

Se avete bisogno di ricercare oggetti di un percorso personalizzato, un'occhiata a org.springframework.beans.factory.config.BeanFactoryPostProcessor e come il org.springframework.beans.factory.config.PropertyPlaceholderConfigurer è implementato.

L'idea di base è che si ottiene i fagioli con le proprietà 'prime', per esempio ${jdbcDriverClassName} e poi si arriva a risolverli e sostituirli con i valori desiderati.

Altri suggerimenti

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>
     

Output:

     
first value
second value

La mia soluzione esistente comporta la definizione di un nuovo MapAwareApplicationContext che prende una mappa come un ulteriore argomento del costruttore.

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

Si sovrascrive postProcessBeanFactory () per aggiungere in un MapAwareProcessor:

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

Il MapAwareProcessor implementa postProcessBeforeInitialization () per iniettare la mappa in qualsiasi tipo che implementa l'interfaccia MapAware:

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

    return bean;
}

Ho quindi aggiungere un nuovo bean al mio config per dichiarare una MapAwarePropertyPlaceholderConfigurer:

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

Il configuratore implementa MapAware, quindi sarà iniettato con mappa come sopra. E poi implementa resolvePlaceholder () per risolvere le proprietà dalla mappa, o delegare al configuratore genitore:

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 può recuperare oggetti di un file, questo è vero, ma se non le trovano, si torna a utilizzare le proprietà del sistema. Questo suona come una valida opzione per l'applicazione client, basta passare la proprietà di sistema utilizzando -D quando si avvia il client.

Da javadoc

  

Un configuratore controllerà anche contro   proprietà di sistema (ad esempio "user.dir") se   esso non può risolvere un segnaposto con   qualsiasi proprietà specificate. Questo   può essere personalizzato tramite   "SystemPropertiesMode".

Creare un'istanza RmiProxyFactoryBean e configurare la proprietà serviceUrl direttamente nel codice:

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();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top