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.util.Environment;
|
||||
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;
|
||||
|
||||
//缓存的key
|
||||
private CombinedKey dynKey;
|
||||
private MultiHashKey dynKey;
|
||||
|
||||
//本地缓存过期时长
|
||||
private Duration localExpire;
|
||||
@@ -94,7 +94,7 @@ public class CacheAction {
|
||||
? Sncp.getResourceType(serviceClass).getSimpleName()
|
||||
: environment.getPropertyValue(cached.hash());
|
||||
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.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
|
||||
*/
|
||||
public interface CombinedKey {
|
||||
public interface MultiHashKey {
|
||||
|
||||
public String keyFor(Object... args);
|
||||
|
||||
/**
|
||||
* 生成Key, paramTypes与paramNames长度必须一致
|
||||
* key只支持带#{}的表达式, 且不能嵌套, 如:name_#{key_#{id}}
|
||||
*
|
||||
* @param paramTypes 参数类型
|
||||
* @param paramNames 参数名
|
||||
* @param key key表达式
|
||||
*
|
||||
* @return CombinedKey
|
||||
* @return MultiHashKey
|
||||
*/
|
||||
public static CombinedKey create(Class[] paramTypes, String[] paramNames, String key) {
|
||||
return CombinedKeys.create(paramTypes, paramNames, key);
|
||||
public static MultiHashKey create(String[] paramNames, String 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