2015-06-25 18 views
18

Bir haritayı doldurmak için genel bir yol varsa, ön ekini yalnızca biliyorsunuzdur. Orada varsayarsakHarita'yı genel yolla doldurmak için ConfigurationProperties'i kullanma

Ben bir harita içinde bu özellik doldurmak için genel bir yol var istiyorum

namespace.prop1=value1 
namespace.prop2=value2 
namespace.iDontKnowThisNameAtCompileTime=anothervalue 

gibi özelliklerin bir demet

@Component 
@ConfigurationProperties("namespace") 
public class MyGenericProps { 
    private Map<String, String> propmap = new HashMap<String, String>(); 

    // setter and getter for propmap omitted 

    public Set<String> returnAllKeys() { 
     return propmap.keySet(); 
    } 
} 

Veya böyle bir şey başka elverişli orada toplamak vardır Ortamdaki tüm PropertySources üzerinde yineleme yapmak yerine tüm özellikleri belirli bir önekle toplamanın yolu nedir?

Teşekkür Hansjoerg

cevap

30

sürece her özellik yerine sadece önceden bilmiyorum olanlar, sen @ConfigurationProperties ile yapabilirsiniz daha haritanın içine eklenen sahip mutlu ol.

@ConfigurationProperties("") 
public class CustomProperties { 

    private final Map<String, String> namespace = new HashMap<>(); 

    public Map<String, String> getNamespace() { 
     return namespace; 
    } 

} 

Bahar Boot o ekleyebilir, böylece harita almak için getNamespace yöntemini kullanır: Eğer namespace altında olan her şeyi kapmak istiyorsan o zaman boş bir önek kullanmak ve namespace adında bir harita için bir alıcı sağlamanız gerekir özellikleri. Örneğin, özellikleri daha derinden yuvalanmış olsaydı

{a=alpha, b=bravo, c=charlie} 

: namespace haritası üç girdileri içerecektir

namespace.a=alpha 
namespace.b=bravo 
namespace.c=charlie 

:

namespace.foo.bar.a=alpha 
namespace.foo.bar.b=bravo 
namespace.foo.bar.c=charlie 

Sonra namespace.foo kullanmak istiyorum Bu özellikleri ile öneki olarak namespace venumaralı getNamespace ile bar venumaralarını yeniden adlandırın.sırasıyla.

@ConfigurationProperties desteğini etkinleştirmek için yapılandırmanıza @EnableConfigurationProperties uygulamalısınız.

@SpringBootApplication 
@EnableConfigurationProperties(CustomProperties.class) 
public class YourApplication { 
    // … 
} 
+0

sen 'neden biz olmamalı üzerinde genişletilebilir: Bu durumda, bu ek açıklama kullanarak yerine onlar için bir @Bean yöntemini sağlayan veya bunları bileşen tarama tarafından keşfedilen olması @Component kullanılarak işlenecek istediğiniz fasulye başvurabilir @ @ConfigurationProperties ile @Component? Önyükleme belgelerinde bitti.Tercihin @EnableConfiguratinoProperties'i kullanmak olduğunu mu söylüyorsunuz? – jst

+0

Acele ediyordum ve kendimi biraz daha iyi anlatmalıydım. Yazdıklarım çok güçlü bir şekilde ifade edildi. '@ ConfigurationProperties' açıklamalı fasulyelerin desteğini açmak için' @ EnableConfigurationProperties' kullanmalısınız. Bu noktada '@ ConfigurationProperties'-açıklamalı sınıfınızı kısayollara yönlendirebilir ve fasulye olarak bildirmekten kaçınabilirsiniz. Önyüklemenin kendi kodunda yaptığı şey budur. Cevabımın birazını hatırlayacağım. –

1

Ben verimli bu işlemek için kendime MapFilter sınıf yazdı. Temel olarak, bir Map oluşturun ve ardından anahtar için bir önek belirterek filtreleyin. Ayrıca kolaylık sağlamak için Properties alan bir kurucu da vardır.

Bunun sadece ana haritayı filtrelediğini unutmayın. Filtrelenmiş haritaya uygulanan herhangi bir değişiklik, silme vb. Dahil olmak üzere taban haritasına da uygulanır, ancak ana haritadaki değişiklikler, bir şeyin yeniden oluşturulmasına neden olana kadar filtrelenmiş haritaya yansıtılmayacaktır. Önceden filtrelenmiş haritaların filtrelenmesi çok kolay (ve verimli) de kolaydır (0).

public class MapFilter<T> implements Map<String, T> { 

    // The enclosed map -- could also be a MapFilter. 
    final private Map<String, T> map; 
    // Use a TreeMap for predictable iteration order. 
    // Store Map.Entry to reflect changes down into the underlying map. 
    // The Key is the shortened string. The entry.key is the full string. 
    final private Map<String, Map.Entry<String, T>> entries = new TreeMap<>(); 
    // The prefix they are looking for in this map. 
    final private String prefix; 

    public MapFilter(Map<String, T> map, String prefix) { 
     // Store my backing map. 
     this.map = map; 
     // Record my prefix. 
     this.prefix = prefix; 
     // Build my entries. 
     rebuildEntries(); 
    } 

    public MapFilter(Map<String, T> map) { 
     this(map, ""); 
    } 

    private synchronized void rebuildEntries() { 
     // Start empty. 
     entries.clear(); 
     // Build my entry set. 
     for (Map.Entry<String, T> e : map.entrySet()) { 
      String key = e.getKey(); 
      // Retain each one that starts with the specified prefix. 
      if (key.startsWith(prefix)) { 
       // Key it on the remainder. 
       String k = key.substring(prefix.length()); 
       // Entries k always contains the LAST occurrence if there are multiples. 
       entries.put(k, e); 
      } 
     } 

    } 

    @Override 
    public String toString() { 
     return "MapFilter (" + prefix + ") of " + map + " containing " + entrySet(); 
    } 

    // Constructor from a properties file. 
    public MapFilter(Properties p, String prefix) { 
     // Properties extends HashTable<Object,Object> so it implements Map. 
     // I need Map<String,T> so I wrap it in a HashMap for simplicity. 
     // Java-8 breaks if we use diamond inference. 
     this(new HashMap<String, T>((Map) p), prefix); 
    } 

    // Helper to fast filter the map. 
    public MapFilter<T> filter(String prefix) { 
     // Wrap me in a new filter. 
     return new MapFilter<>(this, prefix); 
    } 

    // Count my entries. 
    @Override 
    public int size() { 
     return entries.size(); 
    } 

    // Are we empty. 
    @Override 
    public boolean isEmpty() { 
     return entries.isEmpty(); 
    } 

    // Is this key in me? 
    @Override 
    public boolean containsKey(Object key) { 
     return entries.containsKey(key); 
    } 

    // Is this value in me. 
    @Override 
    public boolean containsValue(Object value) { 
     // Walk the values. 
     for (Map.Entry<String, T> e : entries.values()) { 
      if (value.equals(e.getValue())) { 
       // Its there! 
       return true; 
      } 
     } 
     return false; 
    } 

    // Get the referenced value - if present. 
    @Override 
    public T get(Object key) { 
     return get(key, null); 
    } 

    // Get the referenced value - if present. 
    public T get(Object key, T dflt) { 
     Map.Entry<String, T> e = entries.get((String) key); 
     return e != null ? e.getValue() : dflt; 
    } 

    // Add to the underlying map. 
    @Override 
    public T put(String key, T value) { 
     T old = null; 
     // Do I have an entry for it already? 
     Map.Entry<String, T> entry = entries.get(key); 
     // Was it already there? 
     if (entry != null) { 
      // Yes. Just update it. 
      old = entry.setValue(value); 
     } else { 
      // Add it to the map. 
      map.put(prefix + key, value); 
      // Rebuild. 
      rebuildEntries(); 
     } 
     return old; 
    } 

    // Get rid of that one. 
    @Override 
    public T remove(Object key) { 
     // Do I have an entry for it? 
     Map.Entry<String, T> entry = entries.get((String) key); 
     if (entry != null) { 
      entries.remove(key); 
      // Change the underlying map. 
      return map.remove(prefix + key); 
     } 
     return null; 
    } 

    // Add all of them. 
    @Override 
    public void putAll(Map<? extends String, ? extends T> m) { 
     for (Map.Entry<? extends String, ? extends T> e : m.entrySet()) { 
      put(e.getKey(), e.getValue()); 
     } 
    } 

    // Clear everything out. 
    @Override 
    public void clear() { 
     // Just remove mine. 
     // This does not clear the underlying map - perhaps it should remove the filtered entries. 
     for (String key : entries.keySet()) { 
      map.remove(prefix + key); 
     } 
     entries.clear(); 
    } 

    @Override 
    public Set<String> keySet() { 
     return entries.keySet(); 
    } 

    @Override 
    public Collection<T> values() { 
     // Roll them all out into a new ArrayList. 
     List<T> values = new ArrayList<>(); 
     for (Map.Entry<String, T> v : entries.values()) { 
      values.add(v.getValue()); 
     } 
     return values; 
    } 

    @Override 
    public Set<Map.Entry<String, T>> entrySet() { 
     // Roll them all out into a new TreeSet. 
     Set<Map.Entry<String, T>> entrySet = new TreeSet<>(); 
     for (Map.Entry<String, Map.Entry<String, T>> v : entries.entrySet()) { 
      entrySet.add(new Entry<>(v)); 
     } 
     return entrySet; 
    } 

    /** 
    * An entry. 
    * 
    * @param <T> 
    * 
    * The type of the value. 
    */ 
    private static class Entry<T> implements Map.Entry<String, T>, Comparable<Entry<T>> { 

     // Note that entry in the entry is an entry in the underlying map. 
     private final Map.Entry<String, Map.Entry<String, T>> entry; 

     Entry(Map.Entry<String, Map.Entry<String, T>> entry) { 
      this.entry = entry; 
     } 

     @Override 
     public String getKey() { 
      return entry.getKey(); 
     } 

     @Override 
     public T getValue() { 
      // Remember that the value is the entry in the underlying map. 
      return entry.getValue().getValue(); 
     } 

     @Override 
     public T setValue(T newValue) { 
      // Remember that the value is the entry in the underlying map. 
      return entry.getValue().setValue(newValue); 
     } 

     @Override 
     public boolean equals(Object o) { 
      if (!(o instanceof Entry)) { 
       return false; 
      } 
      Entry e = (Entry) o; 
      return getKey().equals(e.getKey()) && getValue().equals(e.getValue()); 
     } 

     @Override 
     public int hashCode() { 
      return getKey().hashCode()^getValue().hashCode(); 
     } 

     @Override 
     public String toString() { 
      return getKey() + "=" + getValue(); 
     } 

     @Override 
     public int compareTo(Entry<T> o) { 
      return getKey().compareTo(o.getKey()); 
     } 
    } 

    // Simple tests. 
    public static void main(String[] args) { 
     String[] samples = { 
      "Some.For.Me", 
      "Some.For.You", 
      "Some.More", 
      "Yet.More"}; 
     Map map = new HashMap(); 
     for (String s : samples) { 
      map.put(s, s); 
     } 
     Map all = new MapFilter(map); 
     Map some = new MapFilter(map, "Some."); 
     Map someFor = new MapFilter(some, "For."); 
     System.out.println("All: " + all); 
     System.out.println("Some: " + some); 
     System.out.println("Some.For: " + someFor); 
    } 
} 
İlgili konular