2013-07-19 2 views
11

क्या @CacheEvict में वाइल्डकार्ड का उपयोग करने का कोई तरीका है?स्प्रिंग @ कैशइवेट वाइल्डकार्ड का उपयोग

मेरे पास बहु-किरायेदारी के साथ एक आवेदन है जिसे कभी-कभी किरायेदार के कैश से सभी डेटा बेदखल करने की आवश्यकता होती है, लेकिन सिस्टम में सभी किरायेदारों की नहीं।

निम्न विधि पर विचार करें:

@CacheEvict(value="users", key="T(Security).getTenant() + *") 
public void deleteOrganization(Organization organization) { 
    ... 
} 

वहाँ वैसे भी यह करने के लिए है:

@Cacheable(value="users", key="T(Security).getTenant() + #user.key") 
public List<User> getUsers(User user) { 
    ... 
} 

तो, मैं की तरह कुछ करना चाहते हैं?

उत्तर

1

ब्रह्मांड में प्रत्येक प्रश्न के 99% के साथ, जवाब है: यह निर्भर करता है। यदि आपका कैश मैनेजर कुछ ऐसा करता है जो उससे संबंधित है, तो बढ़िया। लेकिन ऐसा लगता है कि यह मामला नहीं है।

यदि आप SimpleCacheManager का उपयोग कर रहे हैं, जो स्प्रिंग द्वारा प्रदान किया गया एक मूल इन-मेमोरी कैश प्रबंधक है, तो आप शायद ConcurrentMapCache का उपयोग कर रहे हैं जो वसंत के साथ आता है। यद्यपि कुंजियों में वाइल्डकार्ड से निपटने के लिए ConcurrentMapCache का विस्तार करना संभव नहीं है (क्योंकि कैश स्टोर निजी है और आप इसे एक्सेस नहीं कर सकते हैं), आप इसे अपने कार्यान्वयन के लिए केवल प्रेरणा के रूप में उपयोग कर सकते हैं।

नीचे एक संभावित कार्यान्वयन है (मैंने वास्तव में यह जांचने के अलावा अन्य परीक्षण नहीं किया है कि यह काम कर रहा है या नहीं)। यह evict() विधि पर संशोधन के साथ ConcurrentMapCache की एक सादा प्रति है। अंतर यह है कि evict() का यह संस्करण यह देखने के लिए कुंजी का व्यवहार करता है कि यह एक रेगेक्स है या नहीं। उस स्थिति में, यह स्टोर में सभी चाबियों के माध्यम से पुनरावृत्त होता है और रेगेक्स से मेल खाने वाले लोगों को बेदखल करता है।

package com.sigraweb.cache; 

import java.io.Serializable; 
import java.util.concurrent.ConcurrentHashMap; 
import java.util.concurrent.ConcurrentMap; 

import org.springframework.cache.Cache; 
import org.springframework.cache.support.SimpleValueWrapper; 
import org.springframework.util.Assert; 

public class RegexKeyCache implements Cache { 
    private static final Object NULL_HOLDER = new NullHolder(); 

    private final String name; 

    private final ConcurrentMap<Object, Object> store; 

    private final boolean allowNullValues; 

    public RegexKeyCache(String name) { 
     this(name, new ConcurrentHashMap<Object, Object>(256), true); 
    } 

    public RegexKeyCache(String name, boolean allowNullValues) { 
     this(name, new ConcurrentHashMap<Object, Object>(256), allowNullValues); 
    } 

    public RegexKeyCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues) { 
     Assert.notNull(name, "Name must not be null"); 
     Assert.notNull(store, "Store must not be null"); 
     this.name = name; 
     this.store = store; 
     this.allowNullValues = allowNullValues; 
    } 

    @Override 
    public final String getName() { 
     return this.name; 
    } 

    @Override 
    public final ConcurrentMap<Object, Object> getNativeCache() { 
     return this.store; 
    } 

    public final boolean isAllowNullValues() { 
     return this.allowNullValues; 
    } 

    @Override 
    public ValueWrapper get(Object key) { 
     Object value = this.store.get(key); 
     return toWrapper(value); 
    } 

    @Override 
    @SuppressWarnings("unchecked") 
    public <T> T get(Object key, Class<T> type) { 
     Object value = fromStoreValue(this.store.get(key)); 
     if (value != null && type != null && !type.isInstance(value)) { 
      throw new IllegalStateException("Cached value is not of required type [" + type.getName() + "]: " + value); 
     } 
     return (T) value; 
    } 

    @Override 
    public void put(Object key, Object value) { 
     this.store.put(key, toStoreValue(value)); 
    } 

    @Override 
    public ValueWrapper putIfAbsent(Object key, Object value) { 
     Object existing = this.store.putIfAbsent(key, value); 
     return toWrapper(existing); 
    } 

    @Override 
    public void evict(Object key) { 
     this.store.remove(key); 
     if (key.toString().startsWith("regex:")) { 
      String r = key.toString().replace("regex:", ""); 
      for (Object k : this.store.keySet()) { 
       if (k.toString().matches(r)) { 
        this.store.remove(k); 
       } 
      } 
     } 
    } 

    @Override 
    public void clear() { 
     this.store.clear(); 
    } 

    protected Object fromStoreValue(Object storeValue) { 
     if (this.allowNullValues && storeValue == NULL_HOLDER) { 
      return null; 
     } 
     return storeValue; 
    } 

    protected Object toStoreValue(Object userValue) { 
     if (this.allowNullValues && userValue == null) { 
      return NULL_HOLDER; 
     } 
     return userValue; 
    } 

    private ValueWrapper toWrapper(Object value) { 
     return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null); 
    } 

    @SuppressWarnings("serial") 
    private static class NullHolder implements Serializable { 
    } 
} 

मुझे विश्वास है कि पाठकों को पता है कि कस्टम कैश कार्यान्वयन के साथ कैश प्रबंधक को कैसे प्रारंभ किया जाए। वहाँ बहुत सारे दस्तावेज हैं जो आपको दिखाते हैं कि यह कैसे करें।अपनी परियोजना के बाद ठीक से कॉन्फ़िगर किया गया है, तो आप ऐसा तरह सामान्य रूप से एनोटेशन का उपयोग कर सकते हैं:

@CacheEvict(value = { "cacheName" }, key = "'regex:#tenant'+'.*'") 
public myMethod(String tenant){ 
... 
} 

फिर, यह से ठीक से परीक्षण किया जा रहा दूर है, लेकिन यह आप आप क्या चाहते करने के लिए एक रास्ता देती है। यदि आप एक और कैश प्रबंधक का उपयोग कर रहे हैं, तो आप इसके कैश कार्यान्वयन को समान रूप से बढ़ा सकते हैं।

3

जवाब है: नहीं

और इसे प्राप्त करने के आप क्या चाहते हैं कोई आसान तरीका है।

  1. कैश प्रदाता द्वारा लागू करने के लिए स्प्रिंग कैश एनोटेशन सरल होना आसान होना चाहिए।
  2. कुशल कैशिंग सरल होना चाहिए। एक कुंजी और मूल्य है। यदि कैश में कुंजी पाई जाती है तो मान का उपयोग करें, अन्यथा मान गणना करें और कैश में डालें। कुशल कुंजी में तेज़ और ईमानदार होना चाहिए बराबर() और हैशकोड()। मान लीजिए कि आपने एक किरायेदार से कई जोड़े (कुंजी, मूल्य) को कैश किया है। दक्षता के लिए अलग-अलग कुंजियों में अलग-अलग हैशकोड() होना चाहिए। और आप पूरे किरायेदार को बेदखल करने का फैसला करते हैं। कैश में किरायेदार तत्वों को ढूंढना आसान नहीं है। आपको सभी कैश किए गए जोड़े को फिर से भरना होगा और किरायेदार से जुड़े जोड़े को त्यागना होगा। यह कुशल नहीं है। यह परमाणु नहीं है, इसलिए यह जटिल है और कुछ सिंक्रनाइज़ेशन की आवश्यकता है। सिंक्रनाइज़ेशन कुशल नहीं है।

इसलिए नहीं।

लेकिन, अगर आपको कोई समाधान मिल जाए तो मुझे बताएं, क्योंकि आप जो सुविधा चाहते हैं वह वास्तव में उपयोगी है।

संबंधित मुद्दे