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ự.