Передача свойств в контекст Spring

Я использую Spring для обработки вызовов RMI на какой-то удаленный сервер. Легко построить контекст приложения и получить компонент для удаленных вызовов из клиента:

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

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

однако я не вижу простого способа передать свойства в конфигурацию. Например, если я хочу определить имя хоста для удаленного сервера во время выполнения клиента.

в идеале у меня была бы запись в весеннем контексте, как это:

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

и передайте свойства контексту от клиента в качестве параметра.

Я могу использовать PropertyPlaceholderConfigurer в контексте для замены этих свойств, но, насколько я могу судить, это работает только для свойств, прочитанных из файла.

у меня есть реализация, которая решает это (добавлено в качестве ответа), но я ищу стандартную реализацию Spring, чтобы избежать сворачивания моей собственной. Есть ли другой конфигуратор весны (или что-нибудь еще else), чтобы помочь инициализировать конфигурацию или мне лучше смотреть на Java config для достижения этого?

5 ответов


обновление:

основываясь на обновлении вопроса, мое предложение:

  1. создать ServiceResolver bean, который обрабатывает все, что вам нужно обрабатывать на основе ввода клиента;
  2. объявите этот компонент зависимостью от соответствующих служб;
  3. во время выполнения вы можете обновить / использовать этот компонент, как считаете нужным.

на ServiceResolver может тогда, либо на init-method или при каждом вызове определите значения для вернитесь к клиенту, основываясь, например, на поиске JNDI или переменных среды.

но прежде чем сделать это, вы можете взглянуть на параметры конфигурации доступен. Вы можете либо:

  • добавить файлы свойств, которые не должны присутствовать во время компиляции;
  • поиск значений из JNDI;
  • получить значения из системы.свойства.

Если вам нужно искать свойства из пользовательского местоположение, взгляните на org.springframework.beans.factory.config.BeanFactoryPostProcessor и как есть.

основная идея заключается в том, что вы получаете бобы с "сырыми" свойствами, например ${jdbcDriverClassName} и затем вы получите, чтобы решить их и заменить их желаемыми значениями.


см.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>

выход:

first value
second value

мое существующее решение включает в себя определение нового MapAwareApplicationContext, который принимает карту в качестве дополнительного аргумента конструктора.

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

он переопределяет postProcessBeanFactory () для добавления в MapAwareProcessor:

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

MapAwareProcessor реализует postProcessBeforeInitialization () для внедрения карты в любой тип, реализующий интерфейс MapAware:

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

    return bean;
}

затем я добавляю новый компонент в свою конфигурацию, чтобы объявить MapAwarePropertyPlaceholderConfigurer:

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

конфигуратор реализует MapAware, поэтому он будет введен с картой, как указано выше. Затем он реализует resolvePlaceholder () для разрешения свойств с карты или делегирования родительскому конфигуратору:

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 может извлекать свойства из файла, это правда, но если он не может их найти, он возвращается к использованию системных свойств. Это звучит как жизнеспособный вариант для вашего клиентского приложения, просто передайте системное свойство в using-D при запуске клиента.

с javadoc

конфигуратор также будет проверять свойства системы (например, " пользователь.реж") если он не может разрешить заполнитель любой из заданное свойство. Этот смогите быть подгоняно через "systemPropertiesMode".


создать RmiProxyFactoryBean экземпляр и настроить serviceUrl свойство непосредственно в вашем коде:

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