feat:2.3.0

1. 新增bizNo表达式解析引擎Aviator、SpEl、QL
This commit is contained in:
byteblogs168 2023-09-10 23:12:34 +08:00
parent d7e8cd387e
commit 2c3be456b6
15 changed files with 213 additions and 82 deletions

View File

@ -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>

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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());
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -22,6 +22,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>

View File

@ -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>

View File

@ -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));
}
});

View File

@ -31,6 +31,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

View File

@ -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

View File

@ -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("组名称不能为空");
}