feat:2.3.0
1. 新增bizNo表达式解析引擎Aviator、SpEl、QL
This commit is contained in:
parent
d7e8cd387e
commit
2c3be456b6
@ -49,6 +49,20 @@
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.aviator</groupId>
|
||||
<artifactId>aviator</artifactId>
|
||||
<version>5.3.3</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>QLExpress</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
|
@ -0,0 +1,24 @@
|
||||
package com.aizuda.easy.retry.client.core;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 参数表达式解析引擎
|
||||
*
|
||||
* @author www.byteblogs.com
|
||||
* @date 2023-09-10 12:30:23
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public interface ExpressionEngine {
|
||||
|
||||
/**
|
||||
* 执行表达式
|
||||
* @param expression 表达式
|
||||
*
|
||||
* @param args 参数信息
|
||||
* @param method 方法对象
|
||||
* @return 执行结果
|
||||
*/
|
||||
Object eval(String expression, Object[] args, Method method);
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.aizuda.easy.retry.client.core.expression;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.aizuda.easy.retry.client.core.ExpressionEngine;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author www.byteblogs.com
|
||||
* @date 2023-09-10 12:31:17
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public abstract class AbstractExpressionEngine implements ExpressionEngine {
|
||||
private static final DefaultParameterNameDiscoverer DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||
|
||||
@Override
|
||||
public Object eval(String expression, Object[] args, Method method) {
|
||||
|
||||
if (StringUtils.isBlank(expression)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
|
||||
// 获取参数名称
|
||||
String[] paramNameArr = DISCOVERER.getParameterNames(method);
|
||||
if (ArrayUtils.isEmpty(paramNameArr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, Object> context = new HashMap<>(args.length);
|
||||
for (int i = 0; i < paramNameArr.length; i++) {
|
||||
context.put(paramNameArr[i], args[i]);
|
||||
}
|
||||
|
||||
return doEval(expression, context);
|
||||
}
|
||||
|
||||
protected abstract Object doEval(String expression, Map<String, Object> context);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.aizuda.easy.retry.client.core.expression;
|
||||
|
||||
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;
|
||||
import com.aizuda.easy.retry.common.core.util.JsonUtil;
|
||||
import com.googlecode.aviator.AviatorEvaluator;
|
||||
import com.googlecode.aviator.AviatorEvaluatorInstance;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Aviator 表达式
|
||||
*
|
||||
* @author www.byteblogs.com
|
||||
* @date 2023-09-10 17:34:07
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class AviatorExpressionEngine extends AbstractExpressionEngine{
|
||||
|
||||
private static final AviatorEvaluatorInstance ENGINE = AviatorEvaluator.getInstance();
|
||||
|
||||
@Override
|
||||
protected Object doEval(String expression, Map<String, Object> context) {
|
||||
|
||||
try {
|
||||
return ENGINE.execute(expression, context);
|
||||
} catch (Exception e) {
|
||||
throw new EasyRetryClientException("Aviator表达式解析异常. expression:[{}] context:[{}]",
|
||||
expression, JsonUtil.toJsonString(context), e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.aizuda.easy.retry.client.core.expression;
|
||||
|
||||
import cn.hutool.extra.expression.ExpressionException;
|
||||
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;
|
||||
import com.aizuda.easy.retry.common.core.util.JsonUtil;
|
||||
import com.ql.util.express.DefaultContext;
|
||||
import com.ql.util.express.ExpressRunner;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* QL表达式解析器
|
||||
*
|
||||
* @author www.byteblogs.com
|
||||
* @date 2023-09-10 17:40:34
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class QLExpressEngine extends AbstractExpressionEngine {
|
||||
|
||||
private static final ExpressRunner ENGINE = new ExpressRunner();
|
||||
|
||||
@Override
|
||||
protected Object doEval(String expression, Map<String, Object> context) {
|
||||
|
||||
final DefaultContext<String, Object> defaultContext = new DefaultContext<>();
|
||||
defaultContext.putAll(context);
|
||||
try {
|
||||
return ENGINE.execute(expression, defaultContext, null, true, false);
|
||||
} catch (Exception e) {
|
||||
throw new EasyRetryClientException("QL表达式解析异常. expression:[{}] context:[{}]",
|
||||
expression, JsonUtil.toJsonString(context), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.aizuda.easy.retry.client.core.expression;
|
||||
|
||||
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;
|
||||
import com.aizuda.easy.retry.common.core.util.JsonUtil;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Spel表达式解析引擎
|
||||
*
|
||||
* @author www.byteblogs.com
|
||||
* @date 2023-09-10 12:36:56
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class SpELExpressionEngine extends AbstractExpressionEngine {
|
||||
|
||||
private final static ExpressionParser ENGINE = new SpelExpressionParser();
|
||||
|
||||
@Override
|
||||
protected Object doEval(String expression, Map<String, Object> context) {
|
||||
|
||||
try {
|
||||
final EvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
context.forEach(evaluationContext::setVariable);
|
||||
return ENGINE.parseExpression(expression).getValue(evaluationContext, String.class);
|
||||
} catch (Exception e) {
|
||||
throw new EasyRetryClientException("SpEL表达式解析异常. expression:[{}] context:[{}]",
|
||||
expression, JsonUtil.toJsonString(context), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
package com.aizuda.easy.retry.client.core.loader;
|
||||
|
||||
import cn.hutool.core.util.ServiceLoaderUtil;
|
||||
import com.aizuda.easy.retry.client.core.ExpressionEngine;
|
||||
import com.aizuda.easy.retry.client.core.RetryArgSerializer;
|
||||
import com.aizuda.easy.retry.client.core.event.EasyRetryListener;
|
||||
import com.aizuda.easy.retry.client.core.event.SimpleEasyRetryListener;
|
||||
import com.aizuda.easy.retry.client.core.RetrySiteSnapshotContext;
|
||||
import com.aizuda.easy.retry.client.core.expression.SpELExpressionEngine;
|
||||
import com.aizuda.easy.retry.client.core.intercepter.ThreadLockRetrySiteSnapshotContext;
|
||||
import com.aizuda.easy.retry.client.core.serializer.JacksonSerializer;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@ -58,4 +60,13 @@ public class EasyRetrySpiLoader {
|
||||
return Optional.ofNullable(ServiceLoaderUtil.loadFirst(RetrySiteSnapshotContext.class)).orElse(new ThreadLockRetrySiteSnapshotContext<T>(new ThreadLocal<>()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 表达式引擎SPI类
|
||||
*
|
||||
* @return {@link SpELExpressionEngine} 默认序列化类为SpELExpressionEngine
|
||||
*/
|
||||
public static ExpressionEngine loadExpressionEngine() {
|
||||
return Optional.ofNullable(ServiceLoaderUtil.loadFirst(ExpressionEngine.class)).orElse(new SpELExpressionEngine());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.aizuda.easy.retry.client.core.report;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.aizuda.easy.retry.client.core.ExpressionEngine;
|
||||
import com.aizuda.easy.retry.client.core.IdempotentIdGenerate;
|
||||
import com.aizuda.easy.retry.client.core.Report;
|
||||
import com.aizuda.easy.retry.client.core.RetryArgSerializer;
|
||||
@ -8,9 +9,8 @@ import com.aizuda.easy.retry.client.core.cache.RetryerInfoCache;
|
||||
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties;
|
||||
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;
|
||||
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot;
|
||||
import com.aizuda.easy.retry.client.core.retryer.RetryerInfo;
|
||||
import com.aizuda.easy.retry.client.core.loader.EasyRetrySpiLoader;
|
||||
import com.aizuda.easy.retry.client.core.spel.SPELParamFunction;
|
||||
import com.aizuda.easy.retry.client.core.retryer.RetryerInfo;
|
||||
import com.aizuda.easy.retry.common.core.log.LogUtils;
|
||||
import com.aizuda.easy.retry.common.core.model.IdempotentIdContext;
|
||||
import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO;
|
||||
@ -18,7 +18,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 上报抽象类
|
||||
@ -80,9 +79,9 @@ public abstract class AbstractReport implements Report {
|
||||
retryTaskDTO.setGroupName(EasyRetryProperties.getGroup());
|
||||
retryTaskDTO.setSceneName(scene);
|
||||
|
||||
String bizNoSpel = retryerInfo.getBizNo();
|
||||
Function<Object[], String> spelParamFunction = new SPELParamFunction(bizNoSpel, executorMethod);
|
||||
retryTaskDTO.setBizNo(spelParamFunction.apply(args));
|
||||
String expression = retryerInfo.getBizNo();
|
||||
ExpressionEngine expressionEngine = EasyRetrySpiLoader.loadExpressionEngine();
|
||||
retryTaskDTO.setBizNo((String) expressionEngine.eval(expression, args, executorMethod));
|
||||
return retryTaskDTO;
|
||||
}
|
||||
|
||||
|
@ -1,52 +0,0 @@
|
||||
package com.aizuda.easy.retry.client.core.spel;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author: www.byteblogs.com
|
||||
* @date : 2022-03-03 17:27
|
||||
*/
|
||||
public class SPELParamFunction implements Function<Object[], String> {
|
||||
|
||||
private static DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
private String bizNo;
|
||||
|
||||
private Method method;
|
||||
|
||||
public SPELParamFunction(String bizNo, Method method) {
|
||||
this.bizNo = bizNo;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(Object[] params) {
|
||||
|
||||
if (StringUtils.isBlank(bizNo)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
String[] paramNameArr = discoverer.getParameterNames(method);
|
||||
if (ArrayUtils.isEmpty(paramNameArr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < paramNameArr.length; i++) {
|
||||
context.setVariable(paramNameArr[i], params[i]);
|
||||
}
|
||||
|
||||
return parser.parseExpression(bizNo).getValue(context, String.class);
|
||||
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -33,11 +33,11 @@
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
<version>1.10</version>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>commons-configuration</groupId>-->
|
||||
<!-- <artifactId>commons-configuration</artifactId>-->
|
||||
<!-- <version>1.10</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.aizuda.easy.retry.common.core.util;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.aizuda.easy.retry.common.core.exception.EasyRetryCommonException;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
@ -7,19 +8,15 @@ import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* @author: byteblogs
|
||||
@ -109,8 +106,8 @@ public class JsonUtil {
|
||||
* 内部类,处理Json
|
||||
*/
|
||||
public static class JsonMapper {
|
||||
private static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
||||
private static String YYYY_MM_DD = "yyyy-MM-dd";
|
||||
private final static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
||||
private final static String YYYY_MM_DD = "yyyy-MM-dd";
|
||||
|
||||
private static ObjectMapper objectMapper = jacksonObjectMapper();
|
||||
|
||||
@ -148,14 +145,14 @@ public class JsonUtil {
|
||||
@Override
|
||||
public LocalDate deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
|
||||
String value = jsonParser.getValueAsString();
|
||||
return StringUtils.isBlank(value) ? null : LocalDateTime.parse(value, DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS)).toLocalDate();
|
||||
return StrUtil.isBlank(value) ? null : LocalDateTime.parse(value, DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS)).toLocalDate();
|
||||
}
|
||||
});
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
|
||||
@Override
|
||||
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
|
||||
String value = jsonParser.getValueAsString();
|
||||
return StringUtils.isBlank(value) ? null : LocalDateTime.parse(value, DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS));
|
||||
return StrUtil.isBlank(value) ? null : LocalDateTime.parse(value, DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
@ -1,25 +1,16 @@
|
||||
package com.aizuda.easy.retry.template.datasource.access.task;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.aizuda.easy.retry.template.datasource.access.TaskAccess;
|
||||
import com.aizuda.easy.retry.template.datasource.enums.DbTypeEnum;
|
||||
import com.aizuda.easy.retry.template.datasource.exception.EasyRetryDatasourceException;
|
||||
import com.aizuda.easy.retry.template.datasource.persistence.po.RetryTask;
|
||||
import com.aizuda.easy.retry.template.datasource.utils.RequestDataHelper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: www.byteblogs.com
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.aizuda.easy.retry.template.datasource.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.aizuda.easy.retry.template.datasource.exception.EasyRetryDatasourceException;
|
||||
import com.aizuda.easy.retry.template.datasource.persistence.mapper.GroupConfigMapper;
|
||||
import com.aizuda.easy.retry.template.datasource.persistence.po.GroupConfig;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.aizuda.easy.retry.common.core.context.SpringContext;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -57,7 +57,7 @@ public class RequestDataHelper {
|
||||
*/
|
||||
public static void setPartition(String groupName) {
|
||||
|
||||
if (StringUtils.isBlank(groupName)) {
|
||||
if (StrUtil.isBlank(groupName)) {
|
||||
throw new EasyRetryDatasourceException("组名称不能为空");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user