Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions crane4j-extension/crane4j-extension-redisson/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.crane4j</groupId>
<artifactId>crane4j</artifactId>
<version>2.8.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>crane4j-extension-redisson</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.crane4j</groupId>
<artifactId>crane4j-core</artifactId>
<version>2.8.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.15.6</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package cn.crane4j.extension.redisson;
import cn.crane4j.core.cache.AbstractCacheManager;
import lombok.NonNull;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.redisson.api.RBatch;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@Setter
@Slf4j
public class StringKeyRedissonCacheManger extends AbstractCacheManager {
/**
* Global prefix for all cache keys
*/
@NonNull
private String globalPrefix = "crane4j:cache:";
@NonNull
private RedissonClient redissonClient;
private boolean enableClearCache = false;
public StringKeyRedissonCacheManger(@NonNull RedissonClient redisson) {
this.redissonClient = redisson;
}

/**
* Create cache instance.
*/
@NonNull
@Override
protected RedissonCacheObject doCreateCache(String name,Long expireTime, TimeUnit timeUnit){
return new RedissonCacheObject(name,expireTime,timeUnit);
}

/**
* Get the cache key which is used to store value in redisson.
*/
protected String resolveCacheKey(String cacheName,String key){
return globalPrefix + ":" + cacheName + ":" + key;
}

/**
* Resolve cache value.
* @param value cache value
* @return cache value
*/
protected Object resolveCacheValue(Object value){return value;}

/**
* Clean all cache value for a specified cache object.
*/
protected void cleanCache(String cacheName) {
if (enableClearCache) {
String prefix = globalPrefix + ":" + cacheName + ":*";

long deletedCount = 0;
for (String key : redissonClient.getKeys().getKeysByPattern(prefix)) {
RBucket<Object> rBucket = redissonClient.getBucket(key);
rBucket.delete();
deletedCount++;
}

log.warn("Cleared [{}] keys from cache [{}] by prefix [{}]", deletedCount, cacheName, prefix);
} else {
log.warn("Clearing all cache values is not supported in redis cache [{}]", cacheName);
}
}



/**
* Redis cache object.
*/
protected class RedissonCacheObject extends AbstractCacheObject<String>{
private final long expireTime;
private final TimeUnit timeUnit;
private volatile boolean invalid = false;

protected RedissonCacheObject(String name,Long expireTime,TimeUnit timeUnit){
super(name);
this.expireTime = expireTime;
this.timeUnit = timeUnit;
}

/**
* Clear all cache value.
*/
public void clear(){cleanCache(getName());}

/**
* Add all cache value.
* @param caches value
*/
public void putAll(Map<String,Object> caches){
RBatch rBatch = redissonClient.createBatch();

for(Map.Entry<String,Object> entry : caches.entrySet()){
String key = entry.getKey();
Object value = entry.getValue();
String cacheKey = globalPrefix + ":" + getName() + ":" + key;
RBucket<Object> bucket = redissonClient.getBucket(cacheKey);
bucket.setAsync(value);
rBatch.getBucket(cacheKey).setAsync(value);
}
rBatch.execute();
}




/**
* Get all caches according to the key values.
* @param keys keys
* @return map containing keys and their corresponding values
*/
public Map<String, Object> getAll(Iterable<String> keys) {
Set<String> keySet = StreamSupport.stream(keys.spliterator(), false)
.map(key -> resolveCacheKey(getName(), key))
.collect(Collectors.toCollection(LinkedHashSet::new));

Map<String, Object> results = new LinkedHashMap<>();

RBatch rBatch = redissonClient.createBatch();
for (String key : keySet) {
rBatch.getBucket(key).getAsync();
}

List<?> resultValues = rBatch.execute().getResponses();
int index = 0;
for (String key : keys) {
Object value = resultValues.get(index++);
if (value != null) {
results.put(key, value);
}
}
return results;
}



/**
* Clear all cache value for a specified cache object.
* @param cacheName
*/
protected void cleanCache(String cacheName) {
if (enableClearCache) {
String prefix = globalPrefix + ":" + cacheName + ":*";

Set<String> keys = new HashSet<>();
for (String key : redissonClient.getKeys().getKeysByPattern(prefix)) {
keys.add(key);
}

RBatch rBatch = redissonClient.createBatch();
for (String key : keys) {
rBatch.getBucket(key).deleteAsync();
}
rBatch.execute();

log.warn("Cleared [{}] keys from cache [{}] by prefix [{}]", keys.size(), cacheName, prefix);
} else {
log.warn("Clearing all cache values is not supported in redis cache [{}]", cacheName);
}
}


/**
* Get the cache according to the key value.
* @param key key
* @return cache value
*/
@Nullable
public Object get(String key){
String cacheKey = resolveCacheKey(getName(),key);
RBucket<Object> rBucket = redissonClient.getBucket(cacheKey);
return rBucket.get();
}

/**
* Add cache value.
* @param key key
* @param value value
*/
public void put(String key, Object value){
String cacheKey = resolveCacheKey(getName(),key);
Object cacheValue = resolveCacheValue(value);
RBucket<Object> bucket = redissonClient.getBucket(cacheKey);
bucket.set(cacheValue,expireTime,timeUnit);
}

/**
* Add cache value if it does not exist
* @param key key
* @param value value
*/
public void putIfAbsent(String key, Object value) {
String cacheKey = resolveCacheKey(getName(), key);
RBucket<Object> bucket = redissonClient.getBucket(cacheKey);

if (bucket.isExists()) return;
Object cacheValue = resolveCacheValue(value);
bucket.set(cacheValue, expireTime, timeUnit);
}

/**
* Remove cache value
* @param key key
*/
public void remove(String key){
String cacheKey = resolveCacheKey(getName(),key);
RBucket rBucket = redissonClient.getBucket(cacheKey);
rBucket.delete();
}

/**
* Remove all cache value
* @param keys keys
*/
public void removeAll(Iterable<String> keys) {
Set<String> keySet = StreamSupport.stream(keys.spliterator(), false)
.map(key -> resolveCacheKey(getName(), key))
.collect(Collectors.toSet());

RBatch rBatch = redissonClient.createBatch();

for (String key : keySet) {
RBucket<Object> bucket = redissonClient.getBucket(key);
rBatch.getBucket(bucket.getName()).deleteAsync();
}

rBatch.execute();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package cn.crane4j.extension.redisson;

import cn.crane4j.core.cache.CacheObject;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


public class StringKeyRedissonChangeManagerTest {
private static final String PREFIX = "prefix";
private static final String CACHE_NAME = "test";
private static final long EXPIRE_TIME = 3000L;
private static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS;
private StringKeyRedissonCacheManger cacheManager;
private RedissonClient redissonClient;
private CacheObject<String> cache;

@Before
public void init() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setDatabase(1);
redissonClient = Redisson.create(config);
cacheManager = new StringKeyRedissonCacheManger(redissonClient);
cacheManager.setGlobalPrefix(PREFIX);
cache = cacheManager.createCache("test", EXPIRE_TIME, TIME_UNIT);
}

@Test
public void testPut() {
cache.put("key", "value");
Assert.assertEquals("value", cache.get("key"));
Assert.assertEquals("value", redissonClient.getBucket("prefix:test:key").get());

redissonClient.getBucket("prefix:test:key").delete();



}

@Test
public void testPutAll() {
Map<String, Object> values = new LinkedHashMap<>(2);
values.put("key1", "value1");
values.put("key2", "value2");

cache.putAll(values);

Assert.assertEquals("value1", redissonClient.getBucket("prefix:test:key1").get());
redissonClient.getBucket("prefix:test:key1").delete();
Assert.assertEquals("value2",redissonClient.getBucket("prefix:test:key2").get());
redissonClient.getBucket("prefix:test:key2").delete();
}

@Test
public void testGet() {
cache.put("key", "value");
Assert.assertEquals("value", cache.get("key"));
redissonClient.getBucket("prefix:test:key").delete();
}

@Test
public void testGetAll() {
cache.put("key1", "value1");
cache.put("key2", "value2");
Map<String, Object> map = cache.getAll(Arrays.asList("key1", "none", "key2"));
Assert.assertEquals("value1", map.get("key1"));
Assert.assertEquals("value2", map.get("key2"));
Assert.assertNull(map.get("none"));
redissonClient.getBucket("prefix:test:key1").delete();
redissonClient.getBucket("prefix:test:key2").delete();
}

@Test
public void putIfAbsent() {
cache.put("key1", "value1");
cache.putIfAbsent("key1", "value1");
Assert.assertEquals("value1",redissonClient.getBucket("prefix:test:key1").get());
redissonClient.getBucket("prefix:test:key1").delete();

cache.putIfAbsent("key2", "value2");
Assert.assertEquals("value2", redissonClient.getBucket("prefix:test:key2").get());
redissonClient.getBucket("prefix:test:key2").delete();
}

@Test
public void remove() {
cache.put("key", "value");
cache.remove("key");
redissonClient.getBucket("prefix:test:key").delete();
}

@Test
public void removeAll() {
cache.put("key1", "value1");
cache.put("key2", "value2");
cache.removeAll(Arrays.asList("key1", "key2"));
Assert.assertNull(redissonClient.getBucket("prefix:test:key1").get());
Assert.assertNull(redissonClient.getBucket("prefix:test:key2").get());
}

@Test
public void clear() {
cache.put("key", "value");
cache.clear();
Assert.assertEquals("value", redissonClient.getBucket("prefix:test:key").get());
cacheManager.setEnableClearCache(true);
cache.clear();
Assert.assertNull(redissonClient.getBucket("prefix:test:key").get());
}
}
Loading