MultiHashKey
This commit is contained in:
@@ -17,7 +17,7 @@ import org.redkale.convert.json.JsonConvert;
|
|||||||
import org.redkale.net.sncp.Sncp;
|
import org.redkale.net.sncp.Sncp;
|
||||||
import org.redkale.util.Environment;
|
import org.redkale.util.Environment;
|
||||||
import org.redkale.util.TypeToken;
|
import org.redkale.util.TypeToken;
|
||||||
import org.redkale.util.CombinedKey;
|
import org.redkale.util.MultiHashKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -70,7 +70,7 @@ public class CacheAction {
|
|||||||
private String key;
|
private String key;
|
||||||
|
|
||||||
//缓存的key
|
//缓存的key
|
||||||
private CombinedKey dynKey;
|
private MultiHashKey dynKey;
|
||||||
|
|
||||||
//本地缓存过期时长
|
//本地缓存过期时长
|
||||||
private Duration localExpire;
|
private Duration localExpire;
|
||||||
@@ -94,7 +94,7 @@ public class CacheAction {
|
|||||||
? Sncp.getResourceType(serviceClass).getSimpleName()
|
? Sncp.getResourceType(serviceClass).getSimpleName()
|
||||||
: environment.getPropertyValue(cached.hash());
|
: environment.getPropertyValue(cached.hash());
|
||||||
this.key = environment.getPropertyValue(cached.key());
|
this.key = environment.getPropertyValue(cached.key());
|
||||||
this.dynKey = CombinedKey.create(paramTypes, paramNames, key);
|
this.dynKey = MultiHashKey.create(paramNames, key);
|
||||||
this.localExpire = createDuration(cached.localExpire());
|
this.localExpire = createDuration(cached.localExpire());
|
||||||
this.remoteExpire = createDuration(cached.remoteExpire());
|
this.remoteExpire = createDuration(cached.remoteExpire());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.redkale.util;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
class CombinedKeys {
|
|
||||||
|
|
||||||
public static CombinedKey create(Class[] paramTypes, String[] paramNames, String key) {
|
|
||||||
Objects.requireNonNull(key, "key for " + CombinedKey.class.getSimpleName() + " is null");
|
|
||||||
if ((paramTypes != null && paramNames != null && paramTypes.length != paramNames.length)
|
|
||||||
|| (paramTypes == null && paramNames != null)
|
|
||||||
|| (paramTypes != null && paramNames == null)) {
|
|
||||||
throw new IllegalArgumentException("paramTypes.length and paramNames.length is inconsistent");
|
|
||||||
}
|
|
||||||
if (key.indexOf('{') < 0) {
|
|
||||||
return new StringDynamicKey(key);
|
|
||||||
} else {
|
|
||||||
if (paramNames != null) {
|
|
||||||
for (int i = 0; i < paramNames.length; i++) {
|
|
||||||
if (key.equalsIgnoreCase("#{" + paramNames[i] + "}")) {
|
|
||||||
return new ParamDynamicKey(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new CombinedDynamicKey(paramTypes, paramNames, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class CombinedDynamicKey implements CombinedKey {
|
|
||||||
|
|
||||||
private final CombinedKey[] keys;
|
|
||||||
|
|
||||||
public CombinedDynamicKey(Class[] paramTypes, String[] paramNames, String key) {
|
|
||||||
this.keys = new CombinedKey[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyFor(Object... args) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (CombinedKey key : keys) {
|
|
||||||
sb.append(key.keyFor(args));
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ParamDynamicKey implements CombinedKey {
|
|
||||||
|
|
||||||
private final int index;
|
|
||||||
|
|
||||||
public ParamDynamicKey(int index) {
|
|
||||||
this.index = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyFor(Object... args) {
|
|
||||||
return String.valueOf(args[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class StringDynamicKey implements CombinedKey {
|
|
||||||
|
|
||||||
private final String key;
|
|
||||||
|
|
||||||
public StringDynamicKey(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyFor(Object... args) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private CombinedKeys() {
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -14,20 +14,19 @@ package org.redkale.util;
|
|||||||
*
|
*
|
||||||
* @since 2.8.0
|
* @since 2.8.0
|
||||||
*/
|
*/
|
||||||
public interface CombinedKey {
|
public interface MultiHashKey {
|
||||||
|
|
||||||
public String keyFor(Object... args);
|
public String keyFor(Object... args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成Key, paramTypes与paramNames长度必须一致
|
* key只支持带#{}的表达式, 且不能嵌套, 如:name_#{key_#{id}}
|
||||||
*
|
*
|
||||||
* @param paramTypes 参数类型
|
|
||||||
* @param paramNames 参数名
|
* @param paramNames 参数名
|
||||||
* @param key key表达式
|
* @param key key表达式
|
||||||
*
|
*
|
||||||
* @return CombinedKey
|
* @return MultiHashKey
|
||||||
*/
|
*/
|
||||||
public static CombinedKey create(Class[] paramTypes, String[] paramNames, String key) {
|
public static MultiHashKey create(String[] paramNames, String key) {
|
||||||
return CombinedKeys.create(paramTypes, paramNames, key);
|
return MultiHashKeys.create(paramNames, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
213
src/main/java/org/redkale/util/MultiHashKeys.java
Normal file
213
src/main/java/org/redkale/util/MultiHashKeys.java
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.redkale.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
class MultiHashKeys {
|
||||||
|
|
||||||
|
public static MultiHashKey create(String[] paramNames, String key) {
|
||||||
|
Objects.requireNonNull(key, "key for " + MultiHashKey.class.getSimpleName() + " is null");
|
||||||
|
if (key.indexOf('{') < 0) { //字符串常量
|
||||||
|
return new StringKey(key);
|
||||||
|
} else {
|
||||||
|
Objects.requireNonNull(paramNames, "paramNames for " + MultiHashKey.class.getSimpleName() + " is null");
|
||||||
|
char last = 0;
|
||||||
|
boolean paraming = false;
|
||||||
|
char[] chars = key.toCharArray();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
List<MultiHashKey> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
char ch = chars[i];
|
||||||
|
if (ch == '{') {
|
||||||
|
if (paraming || i < 1) {
|
||||||
|
throw new RedkaleException(MultiHashKey.class.getSimpleName() + " parse error, key: " + key);
|
||||||
|
}
|
||||||
|
if (last == '#') {
|
||||||
|
String name = sb.substring(0, sb.length() - 1);
|
||||||
|
if (!name.isEmpty()) {
|
||||||
|
list.add(new StringKey(name));
|
||||||
|
}
|
||||||
|
sb.delete(0, sb.length());
|
||||||
|
paraming = true;
|
||||||
|
} else {
|
||||||
|
throw new RedkaleException(MultiHashKey.class.getSimpleName() + " parse error, key: " + key);
|
||||||
|
}
|
||||||
|
} else if (ch == '}') {
|
||||||
|
if (!paraming) {
|
||||||
|
throw new RedkaleException(MultiHashKey.class.getSimpleName() + " parse error, key: " + key);
|
||||||
|
}
|
||||||
|
String name = sb.toString();
|
||||||
|
sb.delete(0, sb.length());
|
||||||
|
if (name.indexOf('.') > 0) {
|
||||||
|
list.add(new ParamsKey(paramNames, name));
|
||||||
|
} else {
|
||||||
|
list.add(new ParamKey(paramNames, name));
|
||||||
|
}
|
||||||
|
paraming = false;
|
||||||
|
} else {
|
||||||
|
sb.append(ch);
|
||||||
|
}
|
||||||
|
last = ch;
|
||||||
|
}
|
||||||
|
if (list.size() == 1) {
|
||||||
|
return list.get(0);
|
||||||
|
}
|
||||||
|
return new ArrayKey(list.toArray(new MultiHashKey[list.size()]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ArrayKey implements MultiHashKey {
|
||||||
|
|
||||||
|
private final MultiHashKey[] keys;
|
||||||
|
|
||||||
|
public ArrayKey(MultiHashKey[] keys) {
|
||||||
|
this.keys = keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String keyFor(Object... args) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (MultiHashKey key : keys) {
|
||||||
|
sb.append(key.keyFor(args));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return ArrayKey.class.getSimpleName() + Arrays.toString(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ParamsKey implements MultiHashKey {
|
||||||
|
|
||||||
|
private static final ConcurrentHashMap<String, Attribute> attrCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
private final String fullField;
|
||||||
|
|
||||||
|
private final String[] fields;
|
||||||
|
|
||||||
|
public ParamsKey(int index, String fullField) {
|
||||||
|
this.index = index;
|
||||||
|
this.fullField = fullField;
|
||||||
|
this.fields = fullField.split("\\.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParamsKey(String[] paramNames, String fullField) {
|
||||||
|
int rs = -1;
|
||||||
|
for (int i = 0; i < paramNames.length; i++) {
|
||||||
|
if (fullField.startsWith(paramNames[i] + '.')) {
|
||||||
|
rs = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rs < 0) {
|
||||||
|
throw new RedkaleException(fullField + " not found in " + Arrays.toString(paramNames));
|
||||||
|
}
|
||||||
|
this.index = rs;
|
||||||
|
this.fullField = fullField;
|
||||||
|
this.fields = fullField.split("\\.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String keyFor(Object... args) {
|
||||||
|
return String.valueOf(get(args[index]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object get(Object val) {
|
||||||
|
if (val == null) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
String[] subs = fields;
|
||||||
|
for (int i = 1; i < subs.length; i++) {
|
||||||
|
String fieldName = subs[i];
|
||||||
|
Class clz = val.getClass();
|
||||||
|
Attribute attr = attrCache.computeIfAbsent(clz.getName() + ":" + fieldName, k -> Attribute.create(clz, fieldName));
|
||||||
|
val = attr.get(val);
|
||||||
|
if (val == null) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return ParamsKey.class.getSimpleName() + "{field: " + fullField + ", index: " + index + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ParamKey implements MultiHashKey {
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
private final String field;
|
||||||
|
|
||||||
|
public ParamKey(int index, String field) {
|
||||||
|
this.index = index;
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParamKey(String[] paramNames, String field) {
|
||||||
|
int rs = -1;
|
||||||
|
for (int i = 0; i < paramNames.length; i++) {
|
||||||
|
if (field.equalsIgnoreCase(paramNames[i])) {
|
||||||
|
rs = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rs < 0) {
|
||||||
|
throw new RedkaleException(field + " not found in " + Arrays.toString(paramNames));
|
||||||
|
}
|
||||||
|
this.index = rs;
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String keyFor(Object... args) {
|
||||||
|
return String.valueOf(args[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return ParamKey.class.getSimpleName() + "{field: " + field + ", index: " + index + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StringKey implements MultiHashKey {
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
public StringKey(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String keyFor(Object... args) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return StringKey.class.getSimpleName() + "{key: " + key + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MultiHashKeys() {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
128
src/test/java/org/redkale/test/util/MultiHashKeyTest.java
Normal file
128
src/test/java/org/redkale/test/util/MultiHashKeyTest.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.redkale.test.util;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.redkale.util.MultiHashKey;
|
||||||
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class MultiHashKeyTest {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
MultiHashKeyTest test = new MultiHashKeyTest();
|
||||||
|
test.run1();
|
||||||
|
test.run2();
|
||||||
|
test.run3();
|
||||||
|
test.run4();
|
||||||
|
test.run5();
|
||||||
|
test.run6();
|
||||||
|
test.run7();
|
||||||
|
test.run8();
|
||||||
|
test.run9();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run1() throws Exception {
|
||||||
|
String[] paramNames = {"name", "id"};
|
||||||
|
String key = "#{name}";
|
||||||
|
MultiHashKey rs = MultiHashKey.create(paramNames, key);
|
||||||
|
System.out.println(rs);
|
||||||
|
Assertions.assertEquals("ParamKey{field: name, index: 0}", rs.toString());
|
||||||
|
Assertions.assertEquals("haha", rs.keyFor("haha", 123));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run2() throws Exception {
|
||||||
|
String[] paramNames = {"name", "id"};
|
||||||
|
String key = "#{id}";
|
||||||
|
MultiHashKey rs = MultiHashKey.create(paramNames, key);
|
||||||
|
System.out.println(rs);
|
||||||
|
Assertions.assertEquals("ParamKey{field: id, index: 1}", rs.toString());
|
||||||
|
Assertions.assertEquals("123", rs.keyFor("haha", 123));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run3() throws Exception {
|
||||||
|
String[] paramNames = {"name", "id"};
|
||||||
|
String key = "name";
|
||||||
|
MultiHashKey rs = MultiHashKey.create(paramNames, key);
|
||||||
|
System.out.println(rs);
|
||||||
|
Assertions.assertEquals("StringKey{key: name}", rs.toString());
|
||||||
|
Assertions.assertEquals("name", rs.keyFor("haha", 123));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run4() throws Exception {
|
||||||
|
String[] paramNames = {"name", "id"};
|
||||||
|
String key = "key_#{name}_#{id}_#{name.index}";
|
||||||
|
MultiHashKey rs = MultiHashKey.create(paramNames, key);
|
||||||
|
System.out.println(rs);
|
||||||
|
Assertions.assertEquals("ArrayKey[StringKey{key: key_}, ParamKey{field: name, index: 0}, StringKey{key: _}, "
|
||||||
|
+ "ParamKey{field: id, index: 1}, StringKey{key: _}, "
|
||||||
|
+ "ParamsKey{field: name.index, index: 0}]", rs.toString());
|
||||||
|
Assertions.assertEquals("key_n124_123_124", rs.keyFor(new Name(124), 123));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run5() throws Exception {
|
||||||
|
String[] paramNames = {"map", "id"};
|
||||||
|
String key = "key_#{map.name}_#{id}_#{map.index}";
|
||||||
|
MultiHashKey rs = MultiHashKey.create(paramNames, key);
|
||||||
|
System.out.println(rs);
|
||||||
|
Assertions.assertEquals("ArrayKey[StringKey{key: key_}, "
|
||||||
|
+ "ParamsKey{field: map.name, index: 0}, StringKey{key: _}, "
|
||||||
|
+ "ParamKey{field: id, index: 1}, StringKey{key: _}, "
|
||||||
|
+ "ParamsKey{field: map.index, index: 0}]", rs.toString());
|
||||||
|
Map<String, Object> map = Utility.ofMap("name", "me", "index", 123);
|
||||||
|
Assertions.assertEquals("key_me_123_123", rs.keyFor(map, 123));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run6() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run7() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run8() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run9() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Name {
|
||||||
|
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
public Name(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "n" + index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user