问题
I have a properties file like this:
my.properties file:
app.One.id=1
app.One.val=60
app.Two.id=5
app.Two.val=75
And I read these values into a map property in my bean in Spring config file like this:
spring-config.xml:
<bean id="myBean" class="myClass" scope="singleton">
<property name="myMap">
<map>
<entry key="${app.One.id}" value="${app.One.val}"/>
<entry key="${app.Two.id}" value="${app.Two.val}"/>
</map>
</property>
</bean>
This way if I add a new id/val to the properties file, I must add a row in config xml in order to have the new id/val in myMap.
My question is, is there a way to specify the key-val pairs in spring config file so that the number of key-vals defined in xml can figure out the items in the properties file and create a map. Basically I want to use this xml file in different environments where we use different number of key-value items in properties file. I just don't want to change the xml file in each environment to read in all these values.
Let me know if you need any other details. Any thoughts/comments is appreciated. Thanks!
回答1:
This is done with Spring EL and custom handling.
It was just interesting for me to try it. It works :)
application.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
">
<util:properties id="values" location="values.properties" />
<bean id="hello" class="my.Hello">
<property name="map"
value="#{T(my.Utils).propsToMap(values, '^(app\.\w*)\.id$', '{idGroup}.val')}" />
</bean>
</beans>
Utils.java
package my;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Utils {
public static Map<String, String> propsToMap(Properties props,
String idPatternString, String valuePatternString) {
Map<String, String> map = new HashMap<String, String>();
Pattern idPattern = Pattern.compile(idPatternString);
for (Enumeration<?> en = props.propertyNames(); en.hasMoreElements();) {
String key = (String) en.nextElement();
String mapKey = (String) props.getProperty(key);
if (mapKey != null) {
Matcher idMatcher = idPattern.matcher(key);
if (idMatcher.matches()) {
String valueName = valuePatternString.replace("{idGroup}",
idMatcher.group(1));
String mapValue = props.getProperty(valueName);
if (mapValue != null) {
map.put(mapKey, mapValue);
}
}
}
}
return map;
}
}
Hello.java
package my;
import java.util.Map;
public class Hello {
private Map<String, String> map;
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
}
values.properties
app.One.id=1
app.One.val=60
app.Two.id=5
app.Two.val=75
回答2:
Maybe I did not fully understand the issue here...
What about a simplified approach?
my.properties file:
1=60
5=75
Application Context
<bean id="myProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath: my.properties</value>
</list>
</property>
</bean>
<bean id="myClass" class="com.pakage.MyClass">
<property name="myMap" ref=" myProperties"/>
</bean>
Java Bean
public class MyClass {
private Map<String , String> myMap;
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public Map<String , String> getMyMap(){
return myMap;
}
}
回答3:
It's a classic environment problem.
There are two ways to do this:
- Add an environment string at the end of the appropriate .properties file; pass that value to the app when it starts and let Spring choose the correct one.
- Put those dynamic properties in a database and query for them on startup. The JNDI for the database will pick the right values.
回答4:
I did not find an ideal way to solve this issue to have dynamic map property read into spring configuration info. Using DB was also not an option for us. This is what I found to be the best alternative for this:
Use a standard format for map key/value pair in the properties file eg: key1 | val1, key2 | val2, key3 | val3, ..., keyn | valn
Read this to a String property or List property in configuration bean like here: Use String to List
Let injected java class split the items into map in setter.
I'm going to mark this as answer. If anyone else has better ways to do this, comment it out and I will change it to answer.
来源:https://stackoverflow.com/questions/14760200/reading-a-dynamic-property-map-into-spring-managed-bean