2013-07-19 47 views
11

Có cách nào để sử dụng các ký tự đại diện trong @CacheEvict không?Spring @CacheEvict bằng cách sử dụng các ký tự đại diện

Tôi có một ứng dụng có nhiều thời gian thuê mà đôi khi cần phải xóa tất cả dữ liệu khỏi bộ nhớ cache của người thuê, nhưng không phải của tất cả người thuê trong hệ thống.

Xem xét các phương pháp sau đây:

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

Vì vậy, tôi muốn làm một cái gì đó như:

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

Liệu có cách nào để làm điều đó?

Trả lời

1

Như với 99% của mỗi câu hỏi trong vũ trụ, câu trả lời là: nó phụ thuộc. Nếu trình quản lý bộ nhớ cache của bạn thực hiện điều gì đó có liên quan đến điều đó, tuyệt vời. Nhưng đó không phải là trường hợp.

Nếu bạn đang sử dụng SimpleCacheManager, là trình quản lý bộ nhớ cache cơ bản trong bộ nhớ do Spring cung cấp, có thể bạn đang sử dụng ConcurrentMapCache cũng đi kèm với Spring. Mặc dù không thể mở rộng ConcurrentMapCache để xử lý các ký tự đại diện trong khóa (vì lưu trữ bộ nhớ cache là riêng tư và bạn không thể truy cập nó), bạn chỉ có thể sử dụng nó làm nguồn cảm hứng cho việc triển khai của riêng bạn.

Dưới đây là một triển khai có thể (tôi đã không thực sự kiểm tra nó nhiều hơn là để kiểm tra xem nó có hoạt động không). Đây là một bản sao đơn giản của ConcurrentMapCache với một sửa đổi trên phương pháp evict(). Sự khác biệt là phiên bản evict() này xử lý khóa để xem đó có phải là regex hay không. Trong trường hợp đó, nó lặp qua tất cả các khóa trong cửa hàng và loại bỏ các khóa khớp với regex.

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 { 
    } 
} 

Tôi tin tưởng rằng người đọc biết cách khởi chạy trình quản lý bộ nhớ cache với triển khai bộ nhớ cache tùy chỉnh. Có rất nhiều tài liệu ở đó cho bạn thấy cách thực hiện điều đó.Sau khi dự án của bạn được cấu hình đúng cách, bạn có thể sử dụng chú thích thường như vậy:

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

Một lần nữa, đây là xa đang được thử nghiệm đúng, nhưng nó mang lại cho bạn một cách để làm những gì bạn muốn. Nếu bạn đang sử dụng trình quản lý bộ nhớ cache khác, bạn có thể mở rộng triển khai bộ nhớ cache của nó tương tự.

3

Trả lời là: No.

Và không phải là cách dễ dàng để đạt được những gì bạn muốn.

  1. Chú thích Spring Cache phải đơn giản để dễ thực hiện bởi nhà cung cấp bộ nhớ cache.
  2. Bộ nhớ đệm hiệu quả phải đơn giản. Có một chìa khóa và giá trị. Nếu tìm thấy khóa trong bộ nhớ cache, hãy sử dụng giá trị, nếu không thì tính giá trị và được đặt vào bộ nhớ cache. Khóa hiệu quả phải có tốc độ nhanh và trung thực bằng()mã băm(). Giả sử bạn đã lưu trữ nhiều cặp (khóa, giá trị) từ một đối tượng thuê. Để hiệu quả, các khóa khác nhau phải có mã băm khác nhau (). Và bạn quyết định đuổi toàn bộ người thuê nhà. Không dễ dàng tìm thấy các phần tử của người thuê trong bộ nhớ cache. Bạn phải lặp lại tất cả các cặp được lưu trữ và loại bỏ các cặp thuộc về đối tượng thuê. Nó không hiệu quả. Nó không phải là nguyên tử, vì vậy nó là phức tạp và cần một số đồng bộ hóa. Đồng bộ hóa không hiệu quả.

Do đó không.

Nhưng, nếu bạn tìm thấy giải pháp cho tôi biết, vì tính năng bạn muốn thực sự hữu ích.

Các vấn đề liên quan