Передача свойств в контекст 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 ответов
обновление:
основываясь на обновлении вопроса, мое предложение:
- создать
ServiceResolver
bean, который обрабатывает все, что вам нужно обрабатывать на основе ввода клиента; - объявите этот компонент зависимостью от соответствующих служб;
- во время выполнения вы можете обновить / использовать этот компонент, как считаете нужным.
на 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();