我正在使用Spring来处理对某个远程服务器的RMI调用。可以直接构造应用程序上下文并从客户端获取远程调用的bean:
ApplicationContext context = new ApplicationContext("classpath:context.xml");
MyService myService = (MyService ) context.getBean( "myService " );
但是我没有看到将属性传递到配置的简单方法。例如,如果我想在客户端的运行时确定远程服务器的主机名。
我理想情况下在Spring上下文中有一个条目:
<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实现来避免我自己的。是否有另一个Spring配置程序(或其他任何东西)来帮助初始化配置,或者我最好看看java配置来实现这个目标吗?
答案 0 :(得分:13)
请参阅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
答案 1 :(得分:2)
我现有的解决方案涉及定义一个新的MapAwareApplicationContext,它将Map作为附加的构造函数参数。
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;
}
然后我将一个新bean添加到我的配置中以声明一个MapAwarePropertyPlaceholderConfigurer:
<bean id="propertyConfigurer"
class="com.hsbc.r2ds.spring.MapAwarePropertyPlaceholderConfigurer"/>
configurer实现了MapAware,因此它将使用上面的Map注入。然后,它实现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;
}
答案 2 :(得分:1)
更新:
根据问题更新,我的建议是:
ServiceResolver
bean,根据客户端输入处理您需要处理的任何内容; ServiceResolver
可以在init-method
或每次调用时确定返回客户端的值,例如org.springframework.beans.factory.config.BeanFactoryPostProcessor
。 JNDI查找或环境变量。
但在此之前,您可能需要查看可用的configuration options。你可以:
如果您需要从自定义位置查找属性,请查看org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
以及${jdbcDriverClassName}
的实施方式。
基本的想法是你得到具有'原始'属性的bean,例如{{1}}然后你就可以解决它们并用所需的值替换它们。
答案 3 :(得分:1)
PropertyPlaceholderConfigurer可以从文件中获取属性,这是真的,但是如果它找不到它们,它将回退到使用系统属性。这听起来像是客户端应用程序的可行选项,只需在启动客户端时使用-D传递系统属性。
来自javadoc
配置器也会检查 系统属性(例如“user.dir”)if 它无法解析占位符 任何指定的属性。这个 可以通过定制 “systemPropertiesMode”。
答案 4 :(得分:0)
创建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();