MultiHashKey
This commit is contained in:
@@ -11,8 +11,8 @@
|
||||
| --- | --- | --- |
|
||||
|key|未定义|缓存的key,支持参数动态组合,比如"key_#{id}"|
|
||||
|hash|```DEFAULT_HASH```|缓存的hash, 不能含有':'、'#'、'@'字符|
|
||||
|localExpire|-1|本地缓存过期时长, 0表示永不过期, -1表示不作本地缓存。 <br> 参数值支持方式:<br>  100: 设置数值 <br>  5*60: 乘法表达式,值为300 <br>  ${env.cache.expires}: 读取系统配置项 <br>  #delays: 读取宿主对象的delays字段值作为值,<br>       字段类型必须是int、long数值类型 |
|
||||
|remoteExpire|-1|远程缓存过期时长, 0表示永不过期, -1表示不作远程缓存。 <br> 参数值支持方式:<br>  100: 设置数值 <br>  5*60: 乘法表达式,值为300 <br>  ${env.cache.expires}: 读取系统配置项 <br>  #delays: 读取宿主对象的delays字段值作为值,<br>       字段类型必须是int、long数值类型 |
|
||||
|localExpire|-1|本地缓存过期时长, 0表示永不过期, -1表示不作本地缓存。 <br> 参数值支持方式:<br>  100: 设置数值 <br>  ${env.cache.expires}: 读取系统配置项 |
|
||||
|remoteExpire|-1|远程缓存过期时长, 0表示永不过期, -1表示不作远程缓存。 <br> 参数值支持方式:<br>  100: 设置数值 <br>  ${env.cache.expires}: 读取系统配置项 |
|
||||
|nullable|false|是否可以缓存null值|
|
||||
|timeUnit|```TimeUnit.SECONDS```|时间单位TimeUnit|
|
||||
|comment|未定义|备注描述|
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|name|未定义|名称, 可用于第三方实现的定时任务组件的key, 比如xxl-job的任务标识|
|
||||
|cron|未定义|cron表达式,也可以使用常量值: <br>  @yearly、@annually、@monthly、@weekly、<br>  @daily、@midnight、@hourly、@minutely <br>  @1m、@2m、@3m、@5m、@10m、@15m、@30m <br>  @1h、@2h、@3h、@6h <br>  ${env.scheduling.cron}: 读取系统配置项|
|
||||
|zone|未定义|时区,```cron```有值才有效, 例如: "Asia/Shanghai"|
|
||||
|fixedDelay|-1|延迟时间,负数为无效值,支持参数配置、乘法表达式和对象字段值 <br> 参数值支持方式:<br>  100: 设置数值 <br>  5*60: 乘法表达式,值为300 <br>  ${env.scheduling.fixedDelay}: 读取系统配置项 <br>  #delays: 读取宿主对象的delays字段值作为值, <br>      字段类型必须是int、long数值类型 <br> 值大于0且fixedRate小于0则使用 ScheduledThreadPoolExecutor.scheduleWithFixedDelay |
|
||||
|fixedRate|-1|周期时间,负数为无效值,支持参数配置、乘法表达式和对象字段值 <br> 参数值支持方式:<br>  100: 设置数值 <br>  5*60: 乘法表达式,值为300 <br>  ${env.scheduling.fixedRate}: 读取系统配置项 <br>  #intervals: 读取宿主对象的intervals字段值作为值, <br>        字段类型必须是int、long数值类型 <br> 值大于0且fixedRate小于0则使用 ScheduledThreadPoolExecutor.scheduleAtFixedRate |
|
||||
|initialDelay|-1|起始延迟时间,负数为无效值,支持参数配置、乘法表达式和对象字段值 <br> 参数值支持方式:<br>  100: 设置数值 <br>  5*60: 乘法表达式,值为300 <br>  ${env.scheduling.initialDelay}: 读取系统配置项 <br>  #inits: 读取宿主对象的inits字段值作为值, <br>     字段类型必须是int、long数值类型 <br> 值大于0且fixedRate和fixedDelay小于0则使用 ScheduledThreadPoolExecutor.schedule |
|
||||
|fixedDelay|-1|延迟时间,负数为无效值,支持参数配置、乘法表达式和对象字段值 <br> 参数值支持方式:<br>  100: 设置数值 <br>  ${env.scheduling.fixedDelay}: 读取系统配置项 <br> 值大于0且fixedRate小于0则使用 ScheduledThreadPoolExecutor.scheduleWithFixedDelay |
|
||||
|fixedRate|-1|周期时间,负数为无效值,支持参数配置、乘法表达式和对象字段值 <br> 参数值支持方式:<br>  100: 设置数值 <br>  ${env.scheduling.fixedRate}: 读取系统配置项 <br> 值大于0且fixedRate小于0则使用 ScheduledThreadPoolExecutor.scheduleAtFixedRate |
|
||||
|initialDelay|-1|起始延迟时间,负数为无效值,支持参数配置、乘法表达式和对象字段值 <br> 参数值支持方式:<br>  100: 设置数值 <br>  ${env.scheduling.initialDelay}: 读取系统配置项 <br> 值大于0且fixedRate和fixedDelay小于0则使用 ScheduledThreadPoolExecutor.schedule |
|
||||
|timeUnit|```TimeUnit.SECONDS```|时间单位TimeUnit|
|
||||
|comment|未定义|备注描述|
|
||||
|mode|```LoadMode.LOCAL```|作用于Service模式,默认值为:LOCAL,<br> LOCAL: 表示远程模式的Service对象中的定时任务不起作用|
|
||||
@@ -23,6 +23,14 @@
|
||||
}
|
||||
```
|
||||
|
||||
  <b>数值配置</b>, 系统启动后延迟10分钟后每60分钟执行一次,
|
||||
```java
|
||||
@Scheduled(fixedDelay = "10", fixedRate = "60", timeUnit = TimeUnit.MINUTES)
|
||||
private void task3() {
|
||||
System.out.println(Times.nowMillis() + "执行一次");
|
||||
}
|
||||
```
|
||||
|
||||
  <b>环境配置</b>, 定时间隔时间由环境变量```env.schedule.fixedRate```配置,没配置采用默认值60秒)
|
||||
```java
|
||||
@Scheduled(fixedRate = "${env.schedule.fixedRate:60}")
|
||||
@@ -32,13 +40,6 @@
|
||||
}
|
||||
```
|
||||
|
||||
  <b>支持乘法表达式</b>, 系统启动后延迟10分钟后每60分钟执行一次,
|
||||
```java
|
||||
@Scheduled(fixedDelay = "10", fixedRate = "2*30", timeUnit = TimeUnit.MINUTES)
|
||||
private void task3() {
|
||||
System.out.println(Times.nowMillis() + "执行一次");
|
||||
}
|
||||
```
|
||||
|
||||
## 基本配置
|
||||
```xml
|
||||
|
||||
4
src/main/java/org/redkale/cache/Cached.java
vendored
4
src/main/java/org/redkale/cache/Cached.java
vendored
@@ -44,9 +44,7 @@ public @interface Cached {
|
||||
* 本地缓存过期时长, 0表示永不过期, -1表示不作本地缓存。<br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值
|
||||
* 5*60: 乘法表达式,值为300
|
||||
* ${env.cache.expires}: 读取系统配置项
|
||||
* #delays: 读取宿主对象的delays字段值作为值,字段类型必须是int、long数值类型
|
||||
*
|
||||
* @return 过期时长
|
||||
*/
|
||||
@@ -56,9 +54,7 @@ public @interface Cached {
|
||||
* 远程缓存过期时长, 0表示永不过期, -1表示不作远程缓存。<br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值
|
||||
* 5*60: 乘法表达式,值为300
|
||||
* ${env.cache.expires}: 读取系统配置项
|
||||
* #delays: 读取宿主对象的delays字段值作为值,字段类型必须是int、long数值类型
|
||||
*
|
||||
* @return 过期时长
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,8 @@ import org.redkale.convert.json.JsonConvert;
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @see org.redkale.mq.MessageConsumer
|
||||
*
|
||||
* @author zhangjx
|
||||
*
|
||||
* @since 2.8.0
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
*/
|
||||
package org.redkale.mq;
|
||||
|
||||
import org.redkale.annotation.ClassDepends;
|
||||
import org.redkale.annotation.Component;
|
||||
import org.redkale.service.Local;
|
||||
import org.redkale.util.AnyValue;
|
||||
import org.redkale.annotation.ClassDepends;
|
||||
|
||||
/**
|
||||
* MQ消费器, 实现类必须标记{@link org.redkale.mq.ResourceConsumer}
|
||||
@@ -14,8 +14,11 @@ import org.redkale.annotation.ClassDepends;
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @see org.redkale.mq.MessageConext
|
||||
* @see org.redkale.mq.ResourceConsumer
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <T> 泛型
|
||||
* @param <T> T
|
||||
*
|
||||
* @since 2.8.0
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,8 @@ import org.redkale.convert.ConvertType;
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @see org.redkale.mq.MessageProducer
|
||||
*
|
||||
* @author zhangjx
|
||||
*
|
||||
* @since 2.8.0
|
||||
|
||||
@@ -52,9 +52,7 @@ public @interface Scheduled {
|
||||
* 延迟时间,支持参数配置、乘法表达式和对象字段值 <br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值
|
||||
* 5*60: 乘法表达式,值为300
|
||||
* ${env.scheduling.fixedDelay}: 读取系统配置项
|
||||
* #delays: 读取宿主对象的delays字段值作为值,字段类型必须是int、long数值类型
|
||||
*
|
||||
* 值大于0且fixedRate小于0则使用 ScheduledThreadPoolExecutor.scheduleWithFixedDelay
|
||||
*
|
||||
@@ -66,9 +64,7 @@ public @interface Scheduled {
|
||||
* 周期时间,支持参数配置、乘法表达式和对象字段值 <br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值
|
||||
* 5*60: 乘法表达式,值为300
|
||||
* ${env.scheduling.fixedRate}: 读取系统配置项
|
||||
* #intervals: 读取宿主对象的intervals字段值作为值,字段类型必须是int、long数值类型
|
||||
*
|
||||
* 值大于0则使用 ScheduledThreadPoolExecutor.scheduleAtFixedRate
|
||||
*
|
||||
@@ -80,9 +76,7 @@ public @interface Scheduled {
|
||||
* 起始延迟时间,支持参数配置、乘法表达式和对象字段值 <br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值
|
||||
* 5*60: 乘法表达式,值为300
|
||||
* ${env.scheduling.initialDelay}: 读取系统配置项
|
||||
* #inits: 读取宿主对象的inits字段值作为值,字段类型必须是int、long数值类型
|
||||
*
|
||||
* 值大于0且fixedRate和fixedDelay小于0则使用 ScheduledThreadPoolExecutor.schedule
|
||||
*
|
||||
|
||||
@@ -6,7 +6,6 @@ package org.redkale.schedule.spi;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.time.Duration;
|
||||
@@ -221,9 +220,9 @@ public class ScheduleManagerService implements ScheduleManager, Service {
|
||||
CronExpression cronExpr = CronExpression.parse(cron);
|
||||
return new CronTask(ref, name, method, cronExpr, zoneId);
|
||||
} else {
|
||||
long fixedDelayLong = getLongValue(ref.get(), fixedDelay);
|
||||
long fixedRateLong = getLongValue(ref.get(), fixedRate);
|
||||
long initialDelayLong = getLongValue(ref.get(), initialDelay);
|
||||
long fixedDelayLong = Long.parseLong(fixedDelay);
|
||||
long fixedRateLong = Long.parseLong(fixedRate);
|
||||
long initialDelayLong = Long.parseLong(initialDelay);
|
||||
return new FixedTask(ref, name, method, fixedDelayLong, fixedRateLong, initialDelayLong, timeUnit);
|
||||
}
|
||||
}
|
||||
@@ -270,46 +269,6 @@ public class ScheduleManagerService implements ScheduleManager, Service {
|
||||
return propertyFunc.apply(value);
|
||||
}
|
||||
|
||||
//支持5*60乘法表达式
|
||||
protected long getLongValue(Object service, String value) {
|
||||
if (value.indexOf('*') > -1) {
|
||||
long rs = 1;
|
||||
boolean flag = false;
|
||||
for (String v : value.split("\\*")) {
|
||||
if (!v.trim().isEmpty()) {
|
||||
rs *= Long.parseLong(v.trim());
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
return flag ? rs : -1;
|
||||
} else if (value.indexOf('#') == 0) {
|
||||
try {
|
||||
String fieldName = value.substring(1);
|
||||
Exception ex = null;
|
||||
Field field = null;
|
||||
Class clazz = service.getClass();
|
||||
do {
|
||||
try {
|
||||
field = clazz.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
RedkaleClassLoader.putReflectionField(clazz.getName(), field);
|
||||
break;
|
||||
} catch (NoSuchFieldException fe) {
|
||||
ex = fe;
|
||||
}
|
||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||
if (field == null) {
|
||||
throw ex;
|
||||
}
|
||||
return ((Number) field.get(service)).longValue();
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
} else {
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int start(String scheduleName) {
|
||||
int c = 0;
|
||||
|
||||
@@ -164,7 +164,7 @@ public interface DataSource extends Resourcable {
|
||||
//-------------------------deleteAsync--------------------------
|
||||
/**
|
||||
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||
等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param entitys Entity对象
|
||||
@@ -175,7 +175,7 @@ public interface DataSource extends Resourcable {
|
||||
|
||||
/**
|
||||
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||
等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param entitys Entity对象
|
||||
@@ -191,7 +191,7 @@ public interface DataSource extends Resourcable {
|
||||
|
||||
/**
|
||||
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||
等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param entitys Entity对象
|
||||
@@ -207,7 +207,7 @@ public interface DataSource extends Resourcable {
|
||||
|
||||
/**
|
||||
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||
等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param entitys Entity对象
|
||||
@@ -218,7 +218,7 @@ public interface DataSource extends Resourcable {
|
||||
|
||||
/**
|
||||
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||
等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param entitys Entity对象
|
||||
@@ -234,7 +234,7 @@ public interface DataSource extends Resourcable {
|
||||
|
||||
/**
|
||||
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||
等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {getValues.id} <br>
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param entitys Entity对象
|
||||
|
||||
@@ -60,11 +60,25 @@ public class Environment implements java.io.Serializable {
|
||||
if (val == null || val.isBlank()) {
|
||||
return val;
|
||||
}
|
||||
char last = 0;
|
||||
char[] chars = val.toCharArray();
|
||||
int startIndex = -1;
|
||||
int endIndex = -1;
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char ch = chars[i];
|
||||
if (ch == '{' && last == '$') {
|
||||
startIndex = i - 1;
|
||||
} else if (last != '\\' && ch == '}' && startIndex >= 0) {
|
||||
endIndex = i;
|
||||
break;
|
||||
}
|
||||
last = ch;
|
||||
}
|
||||
|
||||
//${domain}/${path}/xxx ${aa${bbb}}
|
||||
int pos2 = val.indexOf("}");
|
||||
int pos1 = val.lastIndexOf("${", pos2);
|
||||
if (pos1 >= 0 && pos2 > 0) {
|
||||
String key = val.substring(pos1 + 2, pos2);
|
||||
//school_#{name}_${haha_${age}}_${bb}_#{dd} -> school_#{name}_xxx_xxx_#{dd}
|
||||
if (startIndex >= 0 && endIndex > 0) {
|
||||
String key = val.substring(startIndex + 2, endIndex);
|
||||
int pos3 = key.lastIndexOf(':');
|
||||
String defVal = null;
|
||||
if (pos3 > 0) {
|
||||
@@ -77,13 +91,13 @@ public class Environment implements java.io.Serializable {
|
||||
String subVal = properties.getProperty(key);
|
||||
if (subVal != null) {
|
||||
String newVal = getPropertyValue(subVal, envs);
|
||||
return getPropertyValue(val.substring(0, pos1) + newVal + val.substring(pos2 + 1));
|
||||
return getPropertyValue(val.substring(0, startIndex) + newVal + val.substring(endIndex + 1));
|
||||
} else {
|
||||
for (Properties prop : envs) {
|
||||
subVal = prop.getProperty(key);
|
||||
if (subVal != null) {
|
||||
String newVal = getPropertyValue(subVal, envs);
|
||||
return getPropertyValue(val.substring(0, pos1) + newVal + val.substring(pos2 + 1));
|
||||
return getPropertyValue(val.substring(0, startIndex) + newVal + val.substring(endIndex + 1));
|
||||
}
|
||||
}
|
||||
if (pos3 > 0) {
|
||||
@@ -91,8 +105,6 @@ public class Environment implements java.io.Serializable {
|
||||
}
|
||||
throw new RedkaleException("Not found '" + key + "' value");
|
||||
}
|
||||
} else if ((pos1 >= 0 && pos2 < 0) || (pos1 < 0 && pos2 >= 0 && val.indexOf("#{") < 0)) {
|
||||
throw new RedkaleException(val + " is illegal naming");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public interface MultiHashKey {
|
||||
public String keyFor(Object... args);
|
||||
|
||||
/**
|
||||
* key只支持带#{}的表达式, 且不能嵌套, 如:name_#{key_#{id}}
|
||||
* key只支持带#{}的表达式, 且不能嵌套,错误示例:name_#{key_#{id}}
|
||||
*
|
||||
* @param paramNames 参数名
|
||||
* @param key key表达式
|
||||
|
||||
@@ -39,9 +39,15 @@ class MultiHashKeys {
|
||||
}
|
||||
sb.delete(0, sb.length());
|
||||
paraming = true;
|
||||
} else if (last == '\\') {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(ch);
|
||||
} else {
|
||||
throw new RedkaleException(MultiHashKey.class.getSimpleName() + " parse error, key: " + key);
|
||||
}
|
||||
} else if (last == '\\' && ch == '}') {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(ch);
|
||||
} else if (ch == '}') {
|
||||
if (!paraming) {
|
||||
throw new RedkaleException(MultiHashKey.class.getSimpleName() + " parse error, key: " + key);
|
||||
|
||||
38
src/test/java/org/redkale/test/util/EnvironmentTest.java
Normal file
38
src/test/java/org/redkale/test/util/EnvironmentTest.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.test.util;
|
||||
|
||||
import java.util.Properties;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.redkale.util.Environment;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class EnvironmentTest {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
EnvironmentTest test = new EnvironmentTest();
|
||||
test.run1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run1() throws Exception {
|
||||
Properties properties = new Properties();
|
||||
properties.put("age", "18");
|
||||
properties.put("haha_18", "test");
|
||||
properties.put("bb", "tt");
|
||||
|
||||
Environment env = new Environment(properties);
|
||||
String val = env.getPropertyValue("school_#{name}_${haha_${age}}_${bb}_#{dd}");
|
||||
System.out.println(val);
|
||||
Assertions.assertEquals("school_#{name}_test_tt_#{dd}", val);
|
||||
|
||||
val = env.getPropertyValue("${haha_${age}}");
|
||||
System.out.println(val);
|
||||
Assertions.assertEquals("test", val);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user