2009-07-06 13 views
8

Używam Spring do obsługi wywołań RMI do zdalnego serwera. Jest to łatwe do skonstruowania kontekst aplikacji i uzyskać fasoli dla zdalnych wywołań od wewnątrz klienta:Przekazywanie właściwości do kontekstu Spring

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

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

Jednak nie widzę w prosty sposób przekazać właściwości do konfiguracji. Na przykład, jeśli chcę określić nazwę hosta zdalnego serwera w czasie wykonywania w kliencie.

bym najlepiej mieć wpis w kontekście wiosennego takiego:

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

i przekazać właściwości do kontekstu z klienta jako parametr.

mogę użyć PropertyPlaceholderConfigurer w kontekście zastąpienia tych właściwości, ale o ile mogę powiedzieć to działa tylko dla właściwości odczytanych z pliku.

mam implementację, która rozwiązuje ten (dodane jako odpowiedź), ale szukam standardowej implementacji wiosennym uniknąć toczenia moje własne. Czy istnieje jeszcze inny konfigurator Spring (lub cokolwiek innego), który pomoże zainicjować konfigurację, czy lepiej będzie, jeśli spojrzę na konfigurację java, aby to osiągnąć?

+0

Gdzie indziej można by przechowywać swoje właściwości? –

+0

klient może połączyć się z dowolnym serwerem, np. użytkownik może wpisać nazwę hosta w polu tekstowym. Więc nie jest ustalany w czasie kompilacji. –

Odpowiedz

1

Aktualizacja:

podstawie aktualizacji zapytania, moja propozycja jest taka:

  1. Tworzenie ServiceResolver fasoli który obsługuje cokolwiek trzeba obsłużyć w oparciu o dane klienta;
  2. Deklaracja tego komponentu jako zależności od odpowiednich usług;
  3. W czasie wykonywania możesz zaktualizować/użyć tego komponentu, ale uważasz go za odpowiedni.

ServiceResolver można następnie, albo na init-method lub każdego wywołania określenia wartości powrotu do klienta w oparciu o np Wyszukiwanie JNDI lub zmienne środowiskowe.

Ale zanim to zrobi, warto spojrzeć na configuration options dostępne. Możesz:

  • dodać pliki właściwości, które nie muszą być obecne podczas kompilacji;
  • wyszukać wartości z JNDI;
  • pobierz wartości z pliku System.properties.

Jeśli potrzebujesz do wyszukiwania obiektów z niestandardowej lokalizacji, spójrz na org.springframework.beans.factory.config.BeanFactoryPostProcessor i jak org.springframework.beans.factory.config.PropertyPlaceholderConfigurer jest realizowany.

Podstawowym założeniem jest to, że można dostać fasolę z właściwościami „surowych”, na przykład ${jdbcDriverClassName}, a następnie można je rozwiązać i zastąpić je żądanymi wartościami.

+0

Dzięki temu, jak to robi moja obecna implementacja, zaktualizuję moje pytanie, aby to odzwierciedlić. Miałem nadzieję, że istnieje standardowa wiosenna implementacja, dzięki czemu uniknę mojej własnej. –

1

PropertyPlaceholderConfigurer można pobrać właściwości z pliku, to prawda, ale jeśli nie można ich znaleźć, to wraca do korzystania z właściwości systemu.To brzmi jak realna opcja dla aplikacji klienckiej, wystarczy przekazać właściwość systemową przy użyciu opcji -D po uruchomieniu klienta.

Z javadoc

konfiguratora będzie również sprawdzić przed właściwości systemu (na przykład „user.dir”) Jeśli nie może rozwiązać zastępczy z żadnej z wymienionych właściwości. Ten może być dostosowywany za pomocą "systemPropertiesMode" .

2

Moje istniejące rozwiązanie polega na zdefiniowaniu nowego obiektu MapAwareApplicationContext, który pobiera mapę jako dodatkowy argument konstruktora.

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

To nadpisuje postProcessBeanFactory(), aby dodać w MapAwareProcessor:

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

MapAwareProcessor implementuje postProcessBeforeInitialization(), aby wstrzyknąć mapę do dowolnego typu, który implementuje interfejs MapAware:

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

    return bean; 
} 

Dodaję następnie nowy komponent bean do mojej konfiguracji, aby zadeklarować MapAwarePropertyPlaceholderConfigurer:

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

Konfigurator implementuje MapAware, dzięki czemu zostanie wstrzyknięty z Mapą jak wyżej. Następnie realizuje resolvePlaceholder(), aby rozwiązać właściwości z mapy, albo przekazać Configurer dominującej:

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

Dobry panie, to skomplikowane rozwiązanie prostego problemu ... – skaffman

+0

To jest w pewnym sensie, wydaje się, że coś, co powinno być osiągalne bez zbytniego wysiłku, na pewno mniej wysiłku niż to –

+0

Albo możesz użyć BeanFactoryPostProcessor: http://springindepth.com/book/in-depth-ioc-bean- post-procesory-i-beanFactory-post-procesory.html – Talijanac

0

Utwórz instancję RmiProxyFactoryBean i skonfigurować właściwość serviceUrl bezpośrednio w kodzie:

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

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

wyjściowa:

first value 
second value