2017-01-05 1 views
7

Ich verwende Spring-Caching (mit EHCache) auf Serverseite, die den/die Cache-Schlüssel innerhalb von @Cacheable definiert. Das Problem besteht darin, dass verschiedene Clients dieselben Zeichenfolgen senden, die als Schlüssel mit unterschiedlicher Schreibweise verwendet werden, da sie die Groß- und Kleinschreibung berücksichtigen. Das Ergebnis ist, dass meine Caches mehr Objekte enthalten, als sie benötigen.Wie zu vermeiden, Groß-und Kleinschreibung Schlüssel in Spring-Cache?

Beispiel: Sagen wir, ich habe folgendes Caching für eine bestimmte Methode definiert:

@Cacheable(value = "myCache", key="{#myString}") 
public SomeBusinessObject getFoo(String myString, int foo){ 
... 
} 

Jetzt Client A sendet "abc" (klein geschrieben) an den Controller. Der Controller ruft getFoo auf, und "abc" wird als Schlüssel verwendet, um ein Objekt in den Cache zu stellen. Client B sendet "abC" (Großbuchstabe C) und anstelle des zwischengespeicherten Objekts für den Schlüssel "abc" wird ein neues Cache-Objekt für den Schlüssel "abC" erstellt.

Wie kann ich vermeiden, dass die Groß- und Kleinschreibung beachtet wird? Das ist natürlich Arbeits

@Cacheable(value = "myCache", key="{#myString.toLowerCase()}") 
public SomeBusinessObject getFoo(String myString, int foo){ 
... 
} 

:

Ich weiß, ich könnte der Cache-Schlüssel definieren, wie dies klein geschrieben werden. Aber ich suche nach einer allgemeineren Lösung. Ich habe viele Caches und viele Cache-Keys und mache einige @CacheEvict (s) und @CachePut (s) und wenn ich diesen "toLowerCase" -Ansatz verwenden würde, müsste ich immer sicherstellen, dass ich ihn nicht irgendwo vergessen werde.

+0

Vielleicht ist dies nützlich, haben eine eigene KeyGenerator http://stackoverflow.com/questions/27574786/generating-unique-cache-key-with-spring-keygenerator-not-working – gaston

+0

Ich glaube, Sie delegieren zu einer anderen Methode, die das tatsächliche Caching implementiert * nachdem * Sie gewünschte Änderungen an Schlüsseln vornehmen –

Antwort

0

Wie @gaston erwähnt, ersetzt die Lösung den Standard KeyGenerator. Implementieren org.springframework.cache.annotation.CachingConfigurer oder Erweitern org.springframework.cache.annotation.CachingConfigurerSupport in Ihrem Configuration.

@Configuration 
@EnableCaching 
public class AppConfig extends CachingConfigurerSupport { 
    @Override 
    public KeyGenerator keyGenerator() { 
     return new MyKeyGenerator(); 
    } 

    @Bean 
    @Override 
    public CacheManager cacheManager() { 
     //replaced with prefered CacheManager... 
     SimpleCacheManager cacheManager = new SimpleCacheManager(); 
     cacheManager.addCaches(Arrays.asList(new ConcurrentMapCache("default"))); 
     return cacheManager; 
    } 
} 

Hier ist eine Implementierung von org.springframework.cache.interceptor.SimpleKeyGenerator modifiziert.

import java.lang.reflect.Method; 
import org.springframework.cache.interceptor.KeyGenerator; 
import org.springframework.cache.interceptor.SimpleKey; 

public class MyKeyGenerator implements KeyGenerator { 

    @Override 
    public Object generate(Object target, Method method, Object... params) { 
     if (params.length == 0) { 
      return SimpleKey.EMPTY; 
     } 
     if (params.length == 1) { 
      Object param = params[0]; 
      if (param != null) { 
       if (param.getClass().isArray()) { 
        return new MySimpleKey((Object[])param); 
       } else { 
        if (param instanceof String) { 
         return ((String)param).toLowerCase(); 
        } 
        return param; 
       } 
      } 
     } 
     return new MySimpleKey(params); 
    } 
} 

Die ursprüngliche Implementierung erzeugen Schlüssel SimpleKey Klasse, wenn @Cacheable Verfahren mehr als ein Argument hat. Hier ist eine andere Implementierung für die Herstellung von Groß-und Kleinschreibung Schlüssel.

import java.io.Serializable; 
import java.util.Arrays; 
import org.springframework.util.Assert; 
import org.springframework.util.StringUtils; 
@SuppressWarnings("serial") 
public class MySimpleKey implements Serializable { 
    private final Object[] params; 
    private final int hashCode; 

    /** 
    * Create a new {@link SimpleKey} instance. 
    * @param elements the elements of the key 
    */ 
    public MySimpleKey(Object... elements) { 
     Assert.notNull(elements, "Elements must not be null"); 
     Object[] lceles = new Object[elements.length]; 
     this.params = lceles; 
     System.arraycopy(elements, 0, this.params, 0, elements.length); 
     for (int i = 0; i < elements.length; i++) { 
      Object o = elements[i]; 
      if (o instanceof String) { 
       lceles[i] = ((String)o).toLowerCase(); 
      } else { 
       lceles[i] = o; 
      } 
     } 
     this.hashCode = Arrays.deepHashCode(lceles); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return (this == obj || (obj instanceof MySimpleKey 
       && Arrays.deepEquals(this.params, ((MySimpleKey) obj).params))); 
    } 

    @Override 
    public final int hashCode() { 
     return this.hashCode; 
    } 

    @Override 
    public String toString() { 
     return getClass().getSimpleName() + " [" + StringUtils.arrayToCommaDelimitedString(this.params) + "]"; 
    } 
} 
Verwandte Themen