Merge pull request #6374 from seakider/feat_spring_cache_listener

Feat spring cache listener
pull/6379/head
Nikita Koksharov 4 weeks ago committed by GitHub
commit 547a2ea4b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -15,11 +15,15 @@
*/
package org.redisson.spring.cache;
import org.redisson.api.map.event.MapEntryListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
@ -35,6 +39,8 @@ public class CacheConfig {
private long maxIdleTime;
private int maxSize;
private final List<MapEntryListener> listeners = new ArrayList<>();
/**
* Creates config object with
@ -103,6 +109,24 @@ public class CacheConfig {
this.maxIdleTime = maxIdleTime;
}
/**
* listener will invoke if one of the ttl,maxIdleTime,maxSize is set
* listener Is one of the following implementations:
* EntryCreatedListener
* EntryExpiredListener
* EntryRemovedListener
* EntryUpdatedListener
*
* @param listener listener
*/
public void addListener(MapEntryListener listener) {
listeners.add(listener);
}
protected List<MapEntryListener> getListeners() {
return listeners;
}
/**
* Read config objects stored in JSON format from <code>String</code>
*

@ -15,6 +15,14 @@
*/
package org.redisson.spring.cache;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.redisson.api.map.event.MapEntryListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -22,10 +30,6 @@ import java.io.Reader;
import java.net.URL;
import java.util.Map;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
/**
*
* @author Nikita Koksharov
@ -33,9 +37,20 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
*/
public class CacheConfigSupport {
ObjectMapper jsonMapper = new ObjectMapper();
ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
ObjectMapper jsonMapper = createMapper(null);
ObjectMapper yamlMapper = createMapper(new YAMLFactory());
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "class")
public static class ClassMixIn {
}
private ObjectMapper createMapper(JsonFactory mapping) {
ObjectMapper mapper = new ObjectMapper(mapping);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.addMixIn(MapEntryListener.class, ClassMixIn.class);
return mapper;
}
public Map<String, CacheConfig> fromJSON(String content) throws IOException {
return jsonMapper.readValue(content, new TypeReference<Map<String, CacheConfig>>() {});
}

@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.redisson.api.RMap;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.redisson.api.map.event.MapEntryListener;
import org.redisson.client.codec.Codec;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.InitializingBean;
@ -269,6 +270,9 @@ public class RedissonSpringCacheManager implements CacheManager, ResourceLoaderA
cache = oldCache;
} else {
map.setMaxSize(config.getMaxSize());
for (MapEntryListener listener : config.getListeners()) {
map.addListener(listener);
}
}
return cache;
}

@ -5,7 +5,11 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.redisson.RedisDockerTest;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.api.map.event.EntryEvent;
import org.redisson.api.map.event.EntryExpiredListener;
import org.redisson.config.Config;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
@ -23,6 +27,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@ -94,13 +99,15 @@ public class RedissonSpringCacheShortTTLTest extends RedisDockerTest {
@Bean(destroyMethod = "shutdown")
RedissonClient redisson() {
return createInstance();
return createRedisson();
}
@Bean
CacheManager cacheManager(RedissonClient redissonClient) throws IOException {
Map<String, CacheConfig> config = new HashMap<String, CacheConfig>();
config.put("testMap", new CacheConfig(1 * 1000, 1 * 1000));
CacheConfig cacheConfig = new CacheConfig(1 * 1000, 1 * 1000);
cacheConfig.addListener(new SimpleExpireListener());
config.put("testMap", cacheConfig);
return new RedissonSpringCacheManager(redissonClient, config);
}
@ -113,7 +120,7 @@ public class RedissonSpringCacheShortTTLTest extends RedisDockerTest {
@Bean(destroyMethod = "shutdown")
RedissonClient redisson() {
return createInstance();
return createRedisson();
}
@Bean
@ -122,8 +129,28 @@ public class RedissonSpringCacheShortTTLTest extends RedisDockerTest {
}
}
public static class SimpleExpireListener implements EntryExpiredListener<String, RedissonSpringCacheTest.SampleObject> {
@Override
public void onExpired(EntryEvent<String, RedissonSpringCacheTest.SampleObject> event) {
counter.computeIfAbsent(event.getKey(), k -> {
AtomicInteger ac = new AtomicInteger();
ac.incrementAndGet();
return ac;
});
}
}
private static RedissonClient createRedisson() {
Config config = createConfig();
// fix evict time
config.setMinCleanUpDelay(1);
config.setMaxCleanUpDelay(1);
return Redisson.create(config);
}
private static Map<Class<?>, AnnotationConfigApplicationContext> contexts;
private static final Map<String, AtomicInteger> counter = new HashMap<>();
public static List<Class<?>> data() {
return Arrays.asList(Application.class, JsonConfigApplication.class);
@ -165,5 +192,16 @@ public class RedissonSpringCacheShortTTLTest extends RedisDockerTest {
bean.read("object1");
});
}
@ParameterizedTest
@MethodSource("data")
public void testListener(Class<?> contextClass) throws InterruptedException {
AnnotationConfigApplicationContext context = contexts.get(contextClass);
SampleBean bean = context.getBean(SampleBean.class);
bean.store(contextClass.getName(), new SampleObject("name1", "value1"));
Thread.sleep(5000);
assertThat(counter.get(contextClass.getName()).get()).isEqualTo(1);
}
}

@ -1 +1 @@
{"testMap":{"ttl":1000,"maxIdleTime":1000}}
{"testMap":{"ttl":1000,"maxIdleTime":1000,"listeners": [{"class": "org.redisson.spring.cache.RedissonSpringCacheShortTTLTest$SimpleExpireListener"}]}}
Loading…
Cancel
Save