Ist es möglich, Spring @Value zu verwenden, um Werte aus der Eigenschaftendatei der HashMap zuzuordnen?.
Momentan habe ich so etwas und die Zuordnung eines Wertes ist kein Problem. Ich muss jedoch benutzerdefinierte Werte in HashMap-Ablaufdaten zuordnen. Ist so etwas möglich?
@Service
@PropertySource(value = "classpath:my_service.properties")
public class SomeServiceImpl implements SomeService {
@Value("#{conf['service.cache']}")
private final boolean useCache = false;
@Value("#{conf['service.expiration.[<custom name>]']}")
private final HashMap<String, String> expirations = new HashMap<String, String>();
Eigenschaftendatei: 'my_service.properties'
service.cache=true
service.expiration.name1=100
service.expiration.name2=20
Ist es möglich, wie folgt abzubilden: Wert gesetzt
name1 = 100
name2 = 20
Ich mache eine Lösung, die vom vorherigen Beitrag inspiriert ist.
Registrieren Sie die Eigenschaftendatei in der Spring-Konfiguration:
<util:properties id="myProp" location="classpath:my.properties"/>
Und ich erstelle Komponente:
@Component("PropertyMapper")
public class PropertyMapper {
@Autowired
ApplicationContext applicationContext;
public HashMap<String, Object> startWith(String qualifier, String startWith) {
return startWith(qualifier, startWith, false);
}
public HashMap<String, Object> startWith(String qualifier, String startWith, boolean removeStartWith) {
HashMap<String, Object> result = new HashMap<String, Object>();
Object obj = applicationContext.getBean(qualifier);
if (obj instanceof Properties) {
Properties mobileProperties = (Properties)obj;
if (mobileProperties != null) {
for (Entry<Object, Object> e : mobileProperties.entrySet()) {
Object oKey = e.getKey();
if (oKey instanceof String) {
String key = (String)oKey;
if (((String) oKey).startsWith(startWith)) {
if (removeStartWith)
key = key.substring(startWith.length());
result.put(key, e.getValue());
}
}
}
}
}
return result;
}
}
Und wenn ich HashMap alle Eigenschaften zuordnen möchte, die mit einem bestimmten Wert beginnen, mit der Annotation @Value:
@Service
public class MyServiceImpl implements MyService {
@Value("#{PropertyMapper.startWith('myProp', 'service.expiration.', true)}")
private HashMap<String, Object> portalExpirations;
Ist es möglich, Spring @Value zu verwenden, um Werte aus der Eigenschaftendatei der HashMap zuzuordnen?
Ja ist es. Mit ein wenig Code und Spel .
Betrachten Sie zuerst diese singleton Spring-Bean (Sie sollten sie scannen):
@Component("PropertySplitter")
public class PropertySplitter {
/**
* Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2
*/
public Map<String, String> map(String property) {
return this.map(property, ",");
}
/**
* Example: one.example.property = KEY1:VALUE1.1,VALUE1.2;KEY2:VALUE2.1,VALUE2.2
*/
public Map<String, List<String>> mapOfList(String property) {
Map<String, String> map = this.map(property, ";");
Map<String, List<String>> mapOfList = new HashMap<>();
for (Entry<String, String> entry : map.entrySet()) {
mapOfList.put(entry.getKey(), this.list(entry.getValue()));
}
return mapOfList;
}
/**
* Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4
*/
public List<String> list(String property) {
return this.list(property, ",");
}
/**
* Example: one.example.property = VALUE1.1,VALUE1.2;VALUE2.1,VALUE2.2
*/
public List<List<String>> groupedList(String property) {
List<String> unGroupedList = this.list(property, ";");
List<List<String>> groupedList = new ArrayList<>();
for (String group : unGroupedList) {
groupedList.add(this.list(group));
}
return groupedList;
}
private List<String> list(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property);
}
private Map<String, String> map(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(property);
}
}
Hinweis: Die Klasse PropertySplitter
verwendet das Hilfsprogramm Splitter
von Guava. Weitere Informationen finden Sie in Dokumentation .
Dann in einer Bohne von dir:
@Component
public class MyBean {
@Value("#{PropertySplitter.map('${service.expiration}')}")
Map<String, String> propertyAsMap;
}
Und schließlich die Eigenschaft:
service.expiration = name1:100,name2:20
Es ist nicht genau das, wonach Sie gefragt haben, denn dieses PropertySplitter
funktioniert mit einer einzigen Eigenschaft, die transformiert in ein Map
umgewandelt wird, aber ich denke, Sie könnten entweder wechseln Gehen Sie auf diese Art und Weise vor, um Eigenschaften anzugeben, oder ändern Sie den Code PropertySplitter
so, dass er der gewünschten hierarchischen Art und Weise entspricht.
Sie können die SPEL json-ähnliche Syntax verwenden, um eine einfache Map oder eine Map der Liste in die Eigenschaftendatei zu schreiben.
simple.map={'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}
map.of.list={\
'KEY1': {'value1','value2'}, \
'KEY2': {'value3','value4'}, \
'KEY3': {'value5'} \
}
Ich habe \
Für mehrzeilige Eigenschaften verwendet, um die Lesbarkeit zu verbessern
Dann können Sie in Java mit @Value
Wie folgt automatisch darauf zugreifen und es analysieren.
@Value("#{${simple.map}}")
Map<String, String> simpleMap;
@Value("#{${map.of.list}}")
Map<String, List<String>> mapOfList;
Hier mit ${simple.map}
Erhält @Value
Die folgende Zeichenfolge aus der Eigenschaftendatei:
"{'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}"
Dann wird es ausgewertet, als ob es eingebettet wäre
@Value("#{{'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}}")
Weitere Informationen finden Sie in der offiziellen Dokumentation
Ab Spring 4.1.x (ich kann mich jedoch nicht an eine bestimmte Version erinnern) können Sie so etwas tun
@Value("#{${your.properties.key.name}}")
private Map<String, String> myMap;
wobei your.properties.key.name in Ihrer Eigenschaftendatei ungefähr so aussehen sollte
your.properties.key.name={\
name1 : 100, \
name2 : 200 \
}
Stellen Sie einfach sicher, dass Sie das Bean PropertySourcesPlaceholderConfigurer erstellen, damit es sowohl in Ihrer App als auch beim Schreiben von Unit-Test-Code zum Testen des Codes funktioniert. Andernfalls funktioniert der Platzhalter $ {...} für den Eigenschaftswert nicht wie erwartet und Sie werden einige seltsame SpringEL-Fehler sehen.
Die schnellste auf Spring Boot basierende Lösung, die mir einfällt, ist die folgende. In meinem speziellen Beispiel migriere ich Daten von einem System auf ein anderes. Deshalb brauche ich ein Mapping für ein Feld namens priority.
Zuerst habe ich die Eigenschaftendatei (priority-migration.properties) wie folgt erstellt:
my.prefix.priority.0:0
my.prefix.priority.10:1
my.prefix.priority.15:2
my.prefix.priority.20:2
another.prefix.foo:bar
und lege es auf den Klassenpfad.
Angenommen, Sie möchten die Map in einer Spring-Managed-Bean/-Komponente verwenden, kommentieren Sie Ihre Klasse mit:
@Component
@PropertySource("classpath:/priority-migration.properties")
Was Sie tatsächlich in Ihrer Map wollen, sind natürlich nur die Schlüssel/Wert-Paare, denen my.prefix vorangestellt ist, d. H. Dieser Teil:
{
0:0
10:1
15:2
20:2
}
Um dies zu erreichen, müssen Sie Ihre Komponente mit Anmerkungen versehen
@ConfigurationProperties("my.prefix")
und erstelle einen Getter für das Prioritäts-Infix . Letzteres hat sich in meinem Fall als obligatorisch erwiesen (obwohl das Sring Doc sagt, dass es ausreicht, eine Eigenschaftspriorität zu haben und zu initialisieren es mit einem veränderlichen Wert)
private final Map<Integer, Integer> priorityMap = new HashMap<>();
public Map<Integer, Integer> getPriority() {
return priorityMap;
}
Am Ende
Es sieht ungefähr so aus:
@Component
@ConfigurationProperties("my.prefix")
@PropertySource("classpath:/priority-migration.properties")
class PriorityProcessor {
private final Map<Integer, Integer> priorityMap = new HashMap<>();
public Map<Integer, Integer> getPriority() {
return priorityMap;
}
public void process() {
Integer myPriority = priorityMap.get(10)
// use it here
}
}