java 将属性传递给 Spring 上下文
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1086235/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing properties to a Spring context
提问by Rich Seller
I'm using Spring to handle RMI calls to some remote server. It is straightforward to construct an application context and obtain the bean for remote invocations from within the client:
我正在使用 Spring 来处理对某个远程服务器的 RMI 调用。构建应用程序上下文并从客户端获取用于远程调用的 bean 很简单:
ApplicationContext context = new ApplicationContext("classpath:context.xml");
MyService myService = (MyService ) context.getBean( "myService " );
However I don't see a simple way to pass properties into the configuration. For example if I want to determine the host name for the remote server at runtime within the client.
但是,我没有看到将属性传递到配置中的简单方法。例如,如果我想在客户端内的运行时确定远程服务器的主机名。
I'd ideally have an entry in the Spring context like this:
理想情况下,我希望在 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>
and pass the properties to the context from the client as a parameter.
并将属性作为参数从客户端传递给上下文。
I can use a PropertyPlaceholderConfigurer in the context to substitute for these properties, but as far as I can tell this only works for properties read from a file.
我可以在上下文中使用 PropertyPlaceholderConfigurer 来代替这些属性,但据我所知,这只适用于从文件读取的属性。
I have an implementation that addresses this (added as an answer) but I'm looking for a standard Spring implementation to avoid rolling my own. Is there another Spring configurer (or anything else) to help initialise the configuration or am I better off looking at java config to achieve this?
我有一个解决这个问题的实现(作为答案添加),但我正在寻找一个标准的 Spring 实现以避免滚动我自己的。是否有另一个 Spring 配置器(或其他任何东西)来帮助初始化配置,还是我最好查看 java 配置来实现这一点?
采纳答案by Robert Munteanu
Update:
更新:
Based on the question update, my suggestion is:
根据问题更新,我的建议是:
- Create a
ServiceResolverbean which handles whatever you need to handle based on client input; - Declare this bean as a dependency to the relevant services;
- At runtime, you may update / use this bean however you see fit.
- 创建一个
ServiceResolverbean,它可以根据客户端输入处理您需要处理的任何内容; - 将此 bean 声明为相关服务的依赖项;
- 在运行时,您可以根据需要更新/使用此 bean。
The ServiceResolvercan then, either on the init-methodor on each invocation determine the values to return to the client, based on e.g. JNDI lookups or enviroment variables.
所述ServiceResolver可接着,无论是在init-method或在每次调用确定的值,以返回到客户端,基于例如JNDI查找或环境变量。
But before doing that, you might want to take a look at the configuration optionsavailable. You can either:
但在此之前,您可能需要查看可用的配置选项。您可以:
- add property files which don't have to be present at compile-time;
- look up values from JNDI;
- get values from the System.properties.
- 添加在编译时不必存在的属性文件;
- 从 JNDI 中查找值;
- 从 System.properties 获取值。
If you need to lookup properties from a custom location, take a look at org.springframework.beans.factory.config.BeanFactoryPostProcessorand how the org.springframework.beans.factory.config.PropertyPlaceholderConfigureris implemented.
如果你需要从自定义位置查找性能,看看org.springframework.beans.factory.config.BeanFactoryPostProcessor和如何org.springframework.beans.factory.config.PropertyPlaceholderConfigurer实现。
The basic idea is that you get the beans with the 'raw' properties, e.g. ${jdbcDriverClassName}and then you get to resolve them and replace them with the desired values.
基本思想是您获得具有“原始”属性的 bean,例如${jdbcDriverClassName},然后您可以解析它们并将它们替换为所需的值。
回答by Bert van Brakel
See http://forum.springsource.org/showthread.php?t=71815
见http://forum.springsource.org/showthread.php?t=71815
TestClass.javapackage 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.javapackage 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
TestClass.javapackage 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.javapackage 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
回答by Rich Seller
My existing solution involves defining a new MapAwareApplicationContext that takes a Map as an additional constructor argument.
我现有的解决方案涉及定义一个新的 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();
}
It overrides postProcessBeanFactory() to add in a MapAwareProcessor:
它覆盖 postProcessBeanFactory() 以添加到 MapAwareProcessor 中:
protected void postProcessBeanFactory(
final ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new MapAwareProcessor(this.map));
beanFactory.ignoreDependencyInterface(MapAware.class);
}
The MapAwareProcessor implements postProcessBeforeInitialization() to inject the map into any type that implements the MapAware interface:
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;
}
I then add a new bean to my config to declare a MapAwarePropertyPlaceholderConfigurer:
然后我在我的配置中添加一个新 bean 来声明一个 MapAwarePropertyPlaceholderConfigurer:
<bean id="propertyConfigurer"
class="com.hsbc.r2ds.spring.MapAwarePropertyPlaceholderConfigurer"/>
The configurer implements MapAware, so it will be injected with the Map as above. It then implements resolvePlaceholder() to resolve properties from the map, or delegate to the parent 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;
}
回答by skaffman
PropertyPlaceholderConfigurer can fetch properties from a file, that's true, but if it can't find them, it falls back to using system properties. This sounds like a viable option for your client application, just pass the system property in using -D when you launch the client.
PropertyPlaceholderConfigurer 可以从文件中获取属性,这是真的,但如果找不到它们,它会回退到使用系统属性。这听起来像是您的客户端应用程序的可行选项,只需在启动客户端时使用 -D 传递系统属性即可。
From the javadoc
来自javadoc
A configurer will also check against system properties (e.g. "user.dir") if it cannot resolve a placeholder with any of the specified properties. This can be customized via "systemPropertiesMode".
如果配置器无法解析具有任何指定属性的占位符,它还将检查系统属性(例如“user.dir”)。这可以通过“systemPropertiesMode”自定义。
回答by Chin Huang
Create an RmiProxyFactoryBeaninstance and configure the serviceUrlproperty directly in your code:
创建一个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();

