🎯 目标: 设计灵活强大的表达式引擎,支持条件判断、数据计算和动态脚本执行
🤔 为什么需要表达式引擎?
在流程编排中,表达式引擎是实现动态逻辑的核心:
- 🔀 条件判断: 根据运行时数据决定流程走向
- 🧮 数据计算: 对上下文数据进行复杂计算
- 🔄 循环控制: 动态确定循环的继续条件
- 📊 数据转换: 在步骤间转换和映射数据
- 🛡️ 安全执行: 在受控环境中执行用户代码
🏗️ 表达式引擎架构
graph TB
subgraph "表达式接口层 🎯"
A1[ExpressionEvaluator]
A2[Expression]
A3[ExpressionContext]
end
subgraph "解析层 📝"
B1[ExpressionParser]
B2[TokenLexer]
B3[ASTBuilder]
end
subgraph "执行引擎层 ⚡"
C1[SimpleExpressionEvaluator]
C2[ScriptExpressionEvaluator]
C3[SpELExpressionEvaluator]
C4[GroovyExpressionEvaluator]
end
subgraph "函数库层 🔧"
D1[BuiltinFunctions]
D2[MathFunctions]
D3[StringFunctions]
D4[DateFunctions]
D5[CollectionFunctions]
end
subgraph "安全层 🛡️"
E1[SecurityManager]
E2[SandboxEvaluator]
E3[ResourceLimiter]
end
A1 --> B1
A1 --> C1
A1 --> C2
A1 --> C3
A1 --> C4
B1 --> B2
B1 --> B3
C1 --> D1
C2 --> D1
C3 --> D1
C4 --> D1
D1 --> D2
D1 --> D3
D1 --> D4
D1 --> D5
C1 --> E1
C2 --> E2
C3 --> E3
🎯 核心接口设计
java
/**
* 表达式评估器接口
* 负责解析和执行表达式
*/
public interface ExpressionEvaluator {
/**
* 评估表达式并返回结果
* @param expression 表达式字符串
* @param context 执行上下文
* @return 评估结果
* @throws ExpressionEvaluationException 评估异常
*/
Object evaluate(String expression, FlowContext context) throws ExpressionEvaluationException;
/**
* 评估表达式并返回布尔结果
* @param expression 表达式字符串
* @param context 执行上下文
* @return 布尔结果
* @throws ExpressionEvaluationException 评估异常
*/
boolean evaluateBoolean(String expression, FlowContext context) throws ExpressionEvaluationException;
/**
* 评估表达式并返回指定类型的结果
* @param expression 表达式字符串
* @param context 执行上下文
* @param expectedType 期望的结果类型
* @return 指定类型的结果
* @throws ExpressionEvaluationException 评估异常
*/
<T> T evaluate(String expression, FlowContext context, Class<T> expectedType)
throws ExpressionEvaluationException;
/**
* 编译表达式(可选的优化)
* @param expression 表达式字符串
* @return 编译后的表达式对象
* @throws ExpressionCompilationException 编译异常
*/
Expression compile(String expression) throws ExpressionCompilationException;
/**
* 验证表达式语法
* @param expression 表达式字符串
* @return 验证结果
*/
ValidationResult validate(String expression);
/**
* 获取支持的函数列表
* @return 函数名称集合
*/
Set<String> getSupportedFunctions();
/**
* 注册自定义函数
* @param name 函数名称
* @param function 函数实现
*/
void registerFunction(String name, ExpressionFunction function);
}
/**
* 编译后的表达式接口
*/
public interface Expression {
/**
* 执行表达式
* @param context 执行上下文
* @return 执行结果
*/
Object execute(FlowContext context) throws ExpressionEvaluationException;
/**
* 获取表达式字符串
* @return 原始表达式
*/
String getExpressionString();
/**
* 获取表达式依赖的变量
* @return 变量名称集合
*/
Set<String> getDependentVariables();
/**
* 获取表达式类型
* @return 表达式类型
*/
ExpressionType getType();
}
/**
* 表达式函数接口
*/
@FunctionalInterface
public interface ExpressionFunction {
/**
* 执行函数
* @param args 参数数组
* @return 函数结果
* @throws Exception 执行异常
*/
Object apply(Object... args) throws Exception;
}
/**
* 表达式类型枚举
*/
public enum ExpressionType {
SIMPLE, // 简单表达式
SCRIPT, // 脚本表达式
SPEL, // Spring EL表达式
GROOVY, // Groovy表达式
JAVASCRIPT, // JavaScript表达式
KOTLIN // Kotlin表达式
}
🔧 SimpleExpressionEvaluator实现
java
/**
* 简单表达式评估器
* 支持基本的算术、逻辑和比较运算
*/
public class SimpleExpressionEvaluator implements ExpressionEvaluator {
private static final Logger logger = LoggerFactory.getLogger(SimpleExpressionEvaluator.class);
private final Map<String, ExpressionFunction> functions = new ConcurrentHashMap<>();
private final ExpressionParser parser = new SimpleExpressionParser();
private final Map<String, Expression> compiledExpressions = new ConcurrentHashMap<>();
public SimpleExpressionEvaluator() {
registerBuiltinFunctions();
}
@Override
public Object evaluate(String expression, FlowContext context) throws ExpressionEvaluationException {
if (expression == null || expression.trim().isEmpty()) {
return null;
}
try {
Expression compiled = getOrCompileExpression(expression);
return compiled.execute(context);
} catch (Exception e) {
throw new ExpressionEvaluationException(
"表达式评估失败: " + expression, e);
}
}
@Override
public boolean evaluateBoolean(String expression, FlowContext context)
throws ExpressionEvaluationException {
Object result = evaluate(expression, context);
return convertToBoolean(result);
}
@Override
public <T> T evaluate(String expression, FlowContext context, Class<T> expectedType)
throws ExpressionEvaluationException {
Object result = evaluate(expression, context);
return convertToType(result, expectedType);
}
@Override
public Expression compile(String expression) throws ExpressionCompilationException {
try {
return parser.parse(expression, functions);
} catch (Exception e) {
throw new ExpressionCompilationException(
"表达式编译失败: " + expression, e);
}
}
@Override
public ValidationResult validate(String expression) {
try {
compile(expression);
return ValidationResult.success();
} catch (ExpressionCompilationException e) {
return ValidationResult.error(e.getMessage());
}
}
@Override
public Set<String> getSupportedFunctions() {
return new HashSet<>(functions.keySet());
}
@Override
public void registerFunction(String name, ExpressionFunction function) {
functions.put(name, function);
// 清除编译缓存,因为新函数可能影响已编译的表达式
compiledExpressions.clear();
logger.debug("注册表达式函数: {}", name);
}
/**
* 获取或编译表达式
*/
private Expression getOrCompileExpression(String expression) {
return compiledExpressions.computeIfAbsent(expression, this::compile);
}
/**
* 注册内置函数
*/
private void registerBuiltinFunctions() {
// 数学函数
registerFunction("abs", args -> Math.abs(((Number) args[0]).doubleValue()));
registerFunction("max", args -> Math.max(((Number) args[0]).doubleValue(), ((Number) args[1]).doubleValue()));
registerFunction("min", args -> Math.min(((Number) args[0]).doubleValue(), ((Number) args[1]).doubleValue()));
registerFunction("round", args -> Math.round(((Number) args[0]).doubleValue()));
registerFunction("ceil", args -> Math.ceil(((Number) args[0]).doubleValue()));
registerFunction("floor", args -> Math.floor(((Number) args[0]).doubleValue()));
registerFunction("sqrt", args -> Math.sqrt(((Number) args[0]).doubleValue()));
registerFunction("pow", args -> Math.pow(((Number) args[0]).doubleValue(), ((Number) args[1]).doubleValue()));
// 字符串函数
registerFunction("length", args -> args[0].toString().length());
registerFunction("upper", args -> args[0].toString().toUpperCase());
registerFunction("lower", args -> args[0].toString().toLowerCase());
registerFunction("trim", args -> args[0].toString().trim());
registerFunction("substring", args -> {
String str = args[0].toString();
int start = ((Number) args[1]).intValue();
if (args.length > 2) {
int end = ((Number) args[2]).intValue();
return str.substring(start, end);
}
return str.substring(start);
});
registerFunction("contains", args -> args[0].toString().contains(args[1].toString()));
registerFunction("startsWith", args -> args[0].toString().startsWith(args[1].toString()));
registerFunction("endsWith", args -> args[0].toString().endsWith(args[1].toString()));
registerFunction("replace", args -> args[0].toString().replace(args[1].toString(), args[2].toString()));
// 类型转换函数
registerFunction("toInt", args -> Integer.valueOf(args[0].toString()));
registerFunction("toLong", args -> Long.valueOf(args[0].toString()));
registerFunction("toDouble", args -> Double.valueOf(args[0].toString()));
registerFunction("toString", args -> args[0].toString());
registerFunction("toBool", args -> convertToBoolean(args[0]));
// 集合函数
registerFunction("size", args -> {
if (args[0] instanceof Collection) {
return ((Collection<?>) args[0]).size();
} else if (args[0] instanceof Map) {
return ((Map<?, ?>) args[0]).size();
} else if (args[0].getClass().isArray()) {
return Array.getLength(args[0]);
}
return args[0].toString().length();
});
registerFunction("isEmpty", args -> {
if (args[0] == null) return true;
if (args[0] instanceof Collection) {
return ((Collection<?>) args[0]).isEmpty();
} else if (args[0] instanceof Map) {
return ((Map<?, ?>) args[0]).isEmpty();
} else if (args[0].getClass().isArray()) {
return Array.getLength(args[0]) == 0;
}
return args[0].toString().isEmpty();
});
// 日期时间函数
registerFunction("now", args -> System.currentTimeMillis());
registerFunction("today", args -> {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTimeInMillis();
});
// 条件函数
registerFunction("if", args -> {
boolean condition = convertToBoolean(args[0]);
return condition ? args[1] : (args.length > 2 ? args[2] : null);
});
registerFunction("nvl", args -> args[0] != null ? args[0] : args[1]);
logger.info("已注册 {} 个内置函数", functions.size());
}
/**
* 转换为布尔值
*/
private boolean convertToBoolean(Object value) {
if (value == null) {
return false;
}
if (value instanceof Boolean) {
return (Boolean) value;
}
if (value instanceof Number) {
return ((Number) value).doubleValue() != 0;
}
if (value instanceof String) {
String str = (String) value;
return !str.isEmpty() && !"false".equalsIgnoreCase(str) && !"0".equals(str);
}
if (value instanceof Collection) {
return !((Collection<?>) value).isEmpty();
}
return true;
}
/**
* 类型转换
*/
@SuppressWarnings("unchecked")
private <T> T convertToType(Object value, Class<T> expectedType) {
if (value == null) {
return null;
}
if (expectedType.isInstance(value)) {
return (T) value;
}
// 字符串转换
if (expectedType == String.class) {
return (T) value.toString();
}
// 数字转换
if (value instanceof Number) {
Number number = (Number) value;
if (expectedType == Integer.class || expectedType == int.class) {
return (T) Integer.valueOf(number.intValue());
}
if (expectedType == Long.class || expectedType == long.class) {
return (T) Long.valueOf(number.longValue());
}
if (expectedType == Double.class || expectedType == double.class) {
return (T) Double.valueOf(number.doubleValue());
}
if (expectedType == Float.class || expectedType == float.class) {
return (T) Float.valueOf(number.floatValue());
}
}
// 布尔转换
if (expectedType == Boolean.class || expectedType == boolean.class) {
return (T) Boolean.valueOf(convertToBoolean(value));
}
throw new IllegalArgumentException(
String.format("无法将 %s 转换为 %s",
value.getClass().getSimpleName(), expectedType.getSimpleName())
);
}
}
📝 表达式解析器实现
java
/**
* 简单表达式解析器
* 使用递归下降解析算法
*/
public class SimpleExpressionParser implements ExpressionParser {
private static final Logger logger = LoggerFactory.getLogger(SimpleExpressionParser.class);
@Override
public Expression parse(String expression, Map<String, ExpressionFunction> functions)
throws ExpressionCompilationException {
try {
TokenLexer lexer = new TokenLexer(expression);
List<Token> tokens = lexer.tokenize();
if (tokens.isEmpty()) {
return new LiteralExpression(null);
}
ASTBuilder builder = new ASTBuilder(tokens, functions);
ASTNode ast = builder.buildAST();
return new CompiledExpression(expression, ast);
} catch (Exception e) {
throw new ExpressionCompilationException(
"解析表达式失败: " + expression, e);
}
}
/**
* 词法分析器
*/
private static class TokenLexer {
private final String expression;
private int position = 0;
public TokenLexer(String expression) {
this.expression = expression;
}
public List<Token> tokenize() {
List<Token> tokens = new ArrayList<>();
while (position < expression.length()) {
char ch = expression.charAt(position);
if (Character.isWhitespace(ch)) {
position++;
continue;
}
Token token = nextToken();
if (token != null) {
tokens.add(token);
}
}
return tokens;
}
private Token nextToken() {
if (position >= expression.length()) {
return null;
}
char ch = expression.charAt(position);
// 数字
if (Character.isDigit(ch) || ch == '.') {
return readNumber();
}
// 字符串
if (ch == '"' || ch == ''') {
return readString();
}
// 标识符或关键字
if (Character.isLetter(ch) || ch == '_') {
return readIdentifier();
}
// 运算符
return readOperator();
}
private Token readNumber() {
int start = position;
boolean hasDecimal = false;
while (position < expression.length()) {
char ch = expression.charAt(position);
if (Character.isDigit(ch)) {
position++;
} else if (ch == '.' && !hasDecimal) {
hasDecimal = true;
position++;
} else {
break;
}
}
String numberStr = expression.substring(start, position);
Number value = hasDecimal ? Double.valueOf(numberStr) : Long.valueOf(numberStr);
return new Token(TokenType.NUMBER, numberStr, value);
}
private Token readString() {
char quote = expression.charAt(position);
position++; // 跳过开始引号
StringBuilder sb = new StringBuilder();
while (position < expression.length()) {
char ch = expression.charAt(position);
if (ch == quote) {
position++; // 跳过结束引号
break;
} else if (ch == '\' && position + 1 < expression.length()) {
// 转义字符
position++;
char escaped = expression.charAt(position);
switch (escaped) {
case 'n': sb.append('\n'); break;
case 't': sb.append('\t'); break;
case 'r': sb.append('\r'); break;
case '\': sb.append('\'); break;
case '"': sb.append('"'); break;
case ''': sb.append('''); break;
default: sb.append(escaped); break;
}
position++;
} else {
sb.append(ch);
position++;
}
}
return new Token(TokenType.STRING, sb.toString(), sb.toString());
}
private Token readIdentifier() {
int start = position;
while (position < expression.length()) {
char ch = expression.charAt(position);
if (Character.isLetterOrDigit(ch) || ch == '_' || ch == '.') {
position++;
} else {
break;
}
}
String identifier = expression.substring(start, position);
// 检查是否为关键字
TokenType type = getKeywordType(identifier);
if (type != null) {
return new Token(type, identifier, identifier);
}
return new Token(TokenType.IDENTIFIER, identifier, identifier);
}
private Token readOperator() {
char ch = expression.charAt(position);
// 双字符运算符
if (position + 1 < expression.length()) {
String twoChar = expression.substring(position, position + 2);
TokenType type = getOperatorType(twoChar);
if (type != null) {
position += 2;
return new Token(type, twoChar, twoChar);
}
}
// 单字符运算符
String oneChar = String.valueOf(ch);
TokenType type = getOperatorType(oneChar);
if (type != null) {
position++;
return new Token(type, oneChar, oneChar);
}
throw new IllegalArgumentException("未知的字符: " + ch);
}
private TokenType getKeywordType(String keyword) {
switch (keyword.toLowerCase()) {
case "true": return TokenType.BOOLEAN;
case "false": return TokenType.BOOLEAN;
case "null": return TokenType.NULL;
case "and": return TokenType.AND;
case "or": return TokenType.OR;
case "not": return TokenType.NOT;
case "in": return TokenType.IN;
default: return null;
}
}
private TokenType getOperatorType(String operator) {
switch (operator) {
case "+": return TokenType.PLUS;
case "-": return TokenType.MINUS;
case "*": return TokenType.MULTIPLY;
case "/": return TokenType.DIVIDE;
case "%": return TokenType.MODULO;
case "==": return TokenType.EQUALS;
case "!=": return TokenType.NOT_EQUALS;
case "<": return TokenType.LESS_THAN;
case "<=": return TokenType.LESS_EQUALS;
case ">": return TokenType.GREATER_THAN;
case ">=": return TokenType.GREATER_EQUALS;
case "&&": return TokenType.AND;
case "||": return TokenType.OR;
case "!": return TokenType.NOT;
case "(": return TokenType.LEFT_PAREN;
case ")": return TokenType.RIGHT_PAREN;
case "[": return TokenType.LEFT_BRACKET;
case "]": return TokenType.RIGHT_BRACKET;
case ",": return TokenType.COMMA;
case ".": return TokenType.DOT;
default: return null;
}
}
}
/**
* AST构建器
*/
private static class ASTBuilder {
private final List<Token> tokens;
private final Map<String, ExpressionFunction> functions;
private int position = 0;
public ASTBuilder(List<Token> tokens, Map<String, ExpressionFunction> functions) {
this.tokens = tokens;
this.functions = functions;
}
public ASTNode buildAST() {
return parseOrExpression();
}
private ASTNode parseOrExpression() {
ASTNode left = parseAndExpression();
while (match(TokenType.OR)) {
Token operator = previous();
ASTNode right = parseAndExpression();
left = new BinaryOpNode(left, operator, right);
}
return left;
}
private ASTNode parseAndExpression() {
ASTNode left = parseEqualityExpression();
while (match(TokenType.AND)) {
Token operator = previous();
ASTNode right = parseEqualityExpression();
left = new BinaryOpNode(left, operator, right);
}
return left;
}
private ASTNode parseEqualityExpression() {
ASTNode left = parseComparisonExpression();
while (match(TokenType.EQUALS, TokenType.NOT_EQUALS)) {
Token operator = previous();
ASTNode right = parseComparisonExpression();
left = new BinaryOpNode(left, operator, right);
}
return left;
}
private ASTNode parseComparisonExpression() {
ASTNode left = parseAdditiveExpression();
while (match(TokenType.LESS_THAN, TokenType.LESS_EQUALS,
TokenType.GREATER_THAN, TokenType.GREATER_EQUALS)) {
Token operator = previous();
ASTNode right = parseAdditiveExpression();
left = new BinaryOpNode(left, operator, right);
}
return left;
}
private ASTNode parseAdditiveExpression() {
ASTNode left = parseMultiplicativeExpression();
while (match(TokenType.PLUS, TokenType.MINUS)) {
Token operator = previous();
ASTNode right = parseMultiplicativeExpression();
left = new BinaryOpNode(left, operator, right);
}
return left;
}
private ASTNode parseMultiplicativeExpression() {
ASTNode left = parseUnaryExpression();
while (match(TokenType.MULTIPLY, TokenType.DIVIDE, TokenType.MODULO)) {
Token operator = previous();
ASTNode right = parseUnaryExpression();
left = new BinaryOpNode(left, operator, right);
}
return left;
}
private ASTNode parseUnaryExpression() {
if (match(TokenType.NOT, TokenType.MINUS)) {
Token operator = previous();
ASTNode operand = parseUnaryExpression();
return new UnaryOpNode(operator, operand);
}
return parsePostfixExpression();
}
private ASTNode parsePostfixExpression() {
ASTNode left = parsePrimaryExpression();
while (true) {
if (match(TokenType.DOT)) {
Token property = consume(TokenType.IDENTIFIER, "期望属性名");
left = new PropertyAccessNode(left, property);
} else if (match(TokenType.LEFT_BRACKET)) {
ASTNode index = parseOrExpression();
consume(TokenType.RIGHT_BRACKET, "期望 ']'");
left = new IndexAccessNode(left, index);
} else if (match(TokenType.LEFT_PAREN) && left instanceof IdentifierNode) {
// 函数调用
List<ASTNode> arguments = new ArrayList<>();
if (!check(TokenType.RIGHT_PAREN)) {
do {
arguments.add(parseOrExpression());
} while (match(TokenType.COMMA));
}
consume(TokenType.RIGHT_PAREN, "期望 ')')");
left = new FunctionCallNode(((IdentifierNode) left).getName(), arguments, functions);
} else {
break;
}
}
return left;
}
private ASTNode parsePrimaryExpression() {
if (match(TokenType.BOOLEAN)) {
return new LiteralNode(Boolean.valueOf(previous().getLexeme()));
}
if (match(TokenType.NULL)) {
return new LiteralNode(null);
}
if (match(TokenType.NUMBER)) {
return new LiteralNode(previous().getValue());
}
if (match(TokenType.STRING)) {
return new LiteralNode(previous().getValue());
}
if (match(TokenType.IDENTIFIER)) {
return new IdentifierNode(previous().getLexeme());
}
if (match(TokenType.LEFT_PAREN)) {
ASTNode expression = parseOrExpression();
consume(TokenType.RIGHT_PAREN, "期望 ')')");
return expression;
}
throw new RuntimeException("意外的标记: " + peek().getLexeme());
}
private boolean match(TokenType... types) {
for (TokenType type : types) {
if (check(type)) {
advance();
return true;
}
}
return false;
}
private boolean check(TokenType type) {
if (isAtEnd()) return false;
return peek().getType() == type;
}
private Token advance() {
if (!isAtEnd()) position++;
return previous();
}
private boolean isAtEnd() {
return position >= tokens.size();
}
private Token peek() {
return tokens.get(position);
}
private Token previous() {
return tokens.get(position - 1);
}
private Token consume(TokenType type, String message) {
if (check(type)) return advance();
throw new RuntimeException(message + ", 但得到: " + peek().getLexeme());
}
}
}
⚡ ScriptExpressionEvaluator实现
java
/**
* 脚本表达式评估器
* 支持多种脚本语言的动态执行
*/
public class ScriptExpressionEvaluator implements ExpressionEvaluator {
private static final Logger logger = LoggerFactory.getLogger(ScriptExpressionEvaluator.class);
private final Map<String, ScriptEngine> scriptEngines = new ConcurrentHashMap<>();
private final Map<String, ExpressionFunction> functions = new ConcurrentHashMap<>();
private final SecurityManager securityManager;
public ScriptExpressionEvaluator() {
this(new DefaultSecurityManager());
}
public ScriptExpressionEvaluator(SecurityManager securityManager) {
this.securityManager = securityManager;
initializeScriptEngines();
registerBuiltinFunctions();
}
@Override
public Object evaluate(String expression, FlowContext context) throws ExpressionEvaluationException {
ScriptExpression scriptExpr = parseScriptExpression(expression);
try {
return securityManager.executeSecurely(() -> {
ScriptEngine engine = getScriptEngine(scriptExpr.getLanguage());
setupScriptContext(engine, context);
return engine.eval(scriptExpr.getScript());
});
} catch (Exception e) {
throw new ExpressionEvaluationException(
"脚本执行失败: " + expression, e);
}
}
@Override
public boolean evaluateBoolean(String expression, FlowContext context)
throws ExpressionEvaluationException {
Object result = evaluate(expression, context);
return convertToBoolean(result);
}
@Override
public <T> T evaluate(String expression, FlowContext context, Class<T> expectedType)
throws ExpressionEvaluationException {
Object result = evaluate(expression, context);
return convertToType(result, expectedType);
}
@Override
public Expression compile(String expression) throws ExpressionCompilationException {
try {
ScriptExpression scriptExpr = parseScriptExpression(expression);
ScriptEngine engine = getScriptEngine(scriptExpr.getLanguage());
// 尝试编译脚本(如果引擎支持)
if (engine instanceof Compilable) {
CompiledScript compiled = ((Compilable) engine).compile(scriptExpr.getScript());
return new CompiledScriptExpression(expression, scriptExpr.getLanguage(), compiled);
} else {
return new InterpretedScriptExpression(expression, scriptExpr.getLanguage(), scriptExpr.getScript());
}
} catch (Exception e) {
throw new ExpressionCompilationException(
"脚本编译失败: " + expression, e);
}
}
@Override
public ValidationResult validate(String expression) {
try {
compile(expression);
return ValidationResult.success();
} catch (ExpressionCompilationException e) {
return ValidationResult.error(e.getMessage());
}
}
@Override
public Set<String> getSupportedFunctions() {
return new HashSet<>(functions.keySet());
}
@Override
public void registerFunction(String name, ExpressionFunction function) {
functions.put(name, function);
logger.debug("注册脚本函数: {}", name);
}
/**
* 初始化脚本引擎
*/
private void initializeScriptEngines() {
ScriptEngineManager manager = new ScriptEngineManager();
// JavaScript引擎
ScriptEngine jsEngine = manager.getEngineByName("javascript");
if (jsEngine != null) {
scriptEngines.put("javascript", jsEngine);
scriptEngines.put("js", jsEngine);
}
// Groovy引擎
ScriptEngine groovyEngine = manager.getEngineByName("groovy");
if (groovyEngine != null) {
scriptEngines.put("groovy", groovyEngine);
}
// Kotlin引擎
ScriptEngine kotlinEngine = manager.getEngineByName("kotlin");
if (kotlinEngine != null) {
scriptEngines.put("kotlin", kotlinEngine);
scriptEngines.put("kts", kotlinEngine);
}
logger.info("已初始化脚本引擎: {}", scriptEngines.keySet());
}
/**
* 解析脚本表达式
*/
private ScriptExpression parseScriptExpression(String expression) {
// 格式: language:script 或者 直接的脚本代码(默认JavaScript)
int colonIndex = expression.indexOf(':');
if (colonIndex > 0 && colonIndex < 20) { // 语言名不应该太长
String language = expression.substring(0, colonIndex).trim();
String script = expression.substring(colonIndex + 1).trim();
return new ScriptExpression(language, script);
} else {
// 默认使用JavaScript
return new ScriptExpression("javascript", expression);
}
}
/**
* 获取脚本引擎
*/
private ScriptEngine getScriptEngine(String language) {
ScriptEngine engine = scriptEngines.get(language.toLowerCase());
if (engine == null) {
throw new IllegalArgumentException(
"不支持的脚本语言: " + language + ", 可用语言: " + scriptEngines.keySet());
}
return engine;
}
/**
* 设置脚本上下文
*/
private void setupScriptContext(ScriptEngine engine, FlowContext context) {
Bindings bindings = engine.createBindings();
// 添加上下文数据
bindings.put("context", context);
// 添加所有上下文变量
for (Map.Entry<String, Object> entry : context.getAll().entrySet()) {
bindings.put(entry.getKey(), entry.getValue());
}
// 添加自定义函数
for (Map.Entry<String, ExpressionFunction> entry : functions.entrySet()) {
bindings.put(entry.getKey(), entry.getValue());
}
// 添加工具对象
bindings.put("logger", logger);
bindings.put("System", System.class);
bindings.put("Math", Math.class);
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
}
/**
* 注册内置函数
*/
private void registerBuiltinFunctions() {
// 这里可以注册一些脚本专用的函数
registerFunction("print", args -> {
for (Object arg : args) {
System.out.print(arg);
}
return null;
});
registerFunction("println", args -> {
for (Object arg : args) {
System.out.print(arg);
}
System.out.println();
return null;
});
}
/**
* 转换为布尔值
*/
private boolean convertToBoolean(Object value) {
if (value == null) return false;
if (value instanceof Boolean) return (Boolean) value;
if (value instanceof Number) return ((Number) value).doubleValue() != 0;
if (value instanceof String) {
String str = (String) value;
return !str.isEmpty() && !"false".equalsIgnoreCase(str);
}
return true;
}
/**
* 类型转换
*/
@SuppressWarnings("unchecked")
private <T> T convertToType(Object value, Class<T> expectedType) {
if (value == null) return null;
if (expectedType.isInstance(value)) return (T) value;
// 基本的类型转换逻辑(与SimpleExpressionEvaluator类似)
// ...
throw new IllegalArgumentException(
String.format("无法将 %s 转换为 %s",
value.getClass().getSimpleName(), expectedType.getSimpleName())
);
}
/**
* 脚本表达式数据结构
*/
private static class ScriptExpression {
private final String language;
private final String script;
public ScriptExpression(String language, String script) {
this.language = language;
this.script = script;
}
public String getLanguage() { return language; }
public String getScript() { return script; }
}
/**
* 编译后的脚本表达式
*/
private class CompiledScriptExpression implements Expression {
private final String originalExpression;
private final String language;
private final CompiledScript compiledScript;
public CompiledScriptExpression(String originalExpression, String language, CompiledScript compiledScript) {
this.originalExpression = originalExpression;
this.language = language;
this.compiledScript = compiledScript;
}
@Override
public Object execute(FlowContext context) throws ExpressionEvaluationException {
try {
return securityManager.executeSecurely(() -> {
setupScriptContext(compiledScript.getEngine(), context);
return compiledScript.eval();
});
} catch (Exception e) {
throw new ExpressionEvaluationException(
"编译脚本执行失败: " + originalExpression, e);
}
}
@Override
public String getExpressionString() {
return originalExpression;
}
@Override
public Set<String> getDependentVariables() {
// 脚本的依赖变量分析比较复杂,这里简化处理
return Collections.emptySet();
}
@Override
public ExpressionType getType() {
return ExpressionType.valueOf(language.toUpperCase());
}
}
/**
* 解释执行的脚本表达式
*/
private class InterpretedScriptExpression implements Expression {
private final String originalExpression;
private final String language;
private final String script;
public InterpretedScriptExpression(String originalExpression, String language, String script) {
this.originalExpression = originalExpression;
this.language = language;
this.script = script;
}
@Override
public Object execute(FlowContext context) throws ExpressionEvaluationException {
try {
return securityManager.executeSecurely(() -> {
ScriptEngine engine = getScriptEngine(language);
setupScriptContext(engine, context);
return engine.eval(script);
});
} catch (Exception e) {
throw new ExpressionEvaluationException(
"解释脚本执行失败: " + originalExpression, e);
}
}
@Override
public String getExpressionString() {
return originalExpression;
}
@Override
public Set<String> getDependentVariables() {
return Collections.emptySet();
}
@Override
public ExpressionType getType() {
return ExpressionType.valueOf(language.toUpperCase());
}
}
}
🛡️ 安全管理器实现
java
/**
* 表达式安全管理器
* 提供沙箱环境和资源限制
*/
public class DefaultSecurityManager implements SecurityManager {
private static final Logger logger = LoggerFactory.getLogger(DefaultSecurityManager.class);
private final long maxExecutionTime;
private final int maxMemoryUsage;
private final Set<String> allowedClasses;
private final Set<String> forbiddenMethods;
public DefaultSecurityManager() {
this(5000, 10 * 1024 * 1024); // 默认5秒超时,10MB内存限制
}
public DefaultSecurityManager(long maxExecutionTime, int maxMemoryUsage) {
this.maxExecutionTime = maxExecutionTime;
this.maxMemoryUsage = maxMemoryUsage;
this.allowedClasses = initializeAllowedClasses();
this.forbiddenMethods = initializeForbiddenMethods();
}
@Override
public <T> T executeSecurely(Callable<T> task) throws Exception {
// 创建独立的线程执行任务
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
Thread thread = new Thread(r, "expression-executor");
thread.setDaemon(true);
return thread;
});
try {
Future<T> future = executor.submit(() -> {
// 设置安全管理器
SecurityManager oldSecurityManager = System.getSecurityManager();
System.setSecurityManager(new RestrictiveSecurityManager());
try {
return task.call();
} finally {
System.setSecurityManager(oldSecurityManager);
}
});
return future.get(maxExecutionTime, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
throw new ExpressionEvaluationException("表达式执行超时: " + maxExecutionTime + "ms");
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof Exception) {
throw (Exception) cause;
} else {
throw new ExpressionEvaluationException("表达式执行异常", cause);
}
} finally {
executor.shutdownNow();
}
}
/**
* 初始化允许的类
*/
private Set<String> initializeAllowedClasses() {
Set<String> allowed = new HashSet<>();
// 基本类型
allowed.add("java.lang.String");
allowed.add("java.lang.Integer");
allowed.add("java.lang.Long");
allowed.add("java.lang.Double");
allowed.add("java.lang.Float");
allowed.add("java.lang.Boolean");
allowed.add("java.lang.Character");
allowed.add("java.lang.Byte");
allowed.add("java.lang.Short");
// 数学类
allowed.add("java.lang.Math");
allowed.add("java.math.BigDecimal");
allowed.add("java.math.BigInteger");
// 日期时间类
allowed.add("java.util.Date");
allowed.add("java.util.Calendar");
allowed.add("java.time.*");
// 集合类
allowed.add("java.util.List");
allowed.add("java.util.Map");
allowed.add("java.util.Set");
allowed.add("java.util.ArrayList");
allowed.add("java.util.HashMap");
allowed.add("java.util.HashSet");
return allowed;
}
/**
* 初始化禁止的方法
*/
private Set<String> initializeForbiddenMethods() {
Set<String> forbidden = new HashSet<>();
// 系统操作
forbidden.add("System.exit");
forbidden.add("System.gc");
forbidden.add("Runtime.exec");
forbidden.add("Runtime.getRuntime");
// 文件操作
forbidden.add("File.*");
forbidden.add("FileInputStream.*");
forbidden.add("FileOutputStream.*");
// 网络操作
forbidden.add("Socket.*");
forbidden.add("ServerSocket.*");
forbidden.add("URL.*");
forbidden.add("URLConnection.*");
// 反射操作
forbidden.add("Class.forName");
forbidden.add("Method.invoke");
forbidden.add("Constructor.newInstance");
return forbidden;
}
/**
* 限制性安全管理器
*/
private class RestrictiveSecurityManager extends java.lang.SecurityManager {
@Override
public void checkPermission(Permission perm) {
// 检查是否为禁止的操作
String permName = perm.getName();
if (permName.startsWith("exitVM")) {
throw new SecurityException("禁止退出虚拟机");
}
if (permName.startsWith("createClassLoader")) {
throw new SecurityException("禁止创建类加载器");
}
if (permName.startsWith("setSecurityManager")) {
throw new SecurityException("禁止设置安全管理器");
}
if (perm instanceof FilePermission) {
throw new SecurityException("禁止文件操作: " + permName);
}
if (perm instanceof SocketPermission) {
throw new SecurityException("禁止网络操作: " + permName);
}
if (perm instanceof RuntimePermission) {
if (permName.startsWith("createClassLoader") ||
permName.startsWith("setContextClassLoader") ||
permName.startsWith("enableContextClassLoaderOverride")) {
throw new SecurityException("禁止类加载器操作: " + permName);
}
}
}
@Override
public void checkExec(String cmd) {
throw new SecurityException("禁止执行外部命令: " + cmd);
}
@Override
public void checkRead(String file) {
throw new SecurityException("禁止读取文件: " + file);
}
@Override
public void checkWrite(String file) {
throw new SecurityException("禁止写入文件: " + file);
}
@Override
public void checkDelete(String file) {
throw new SecurityException("禁止删除文件: " + file);
}
@Override
public void checkConnect(String host, int port) {
throw new SecurityException("禁止网络连接: " + host + ":" + port);
}
}
}
🧪 表达式引擎测试
java
public class ExpressionEvaluatorTest {
private ExpressionEvaluator simpleEvaluator;
private ExpressionEvaluator scriptEvaluator;
private FlowContext context;
@Before
public void setUp() {
simpleEvaluator = new SimpleExpressionEvaluator();
scriptEvaluator = new ScriptExpressionEvaluator();
context = new DefaultFlowContext();
// 设置测试数据
context.put("name", "张三");
context.put("age", 25);
context.put("score", 85.5);
context.put("active", true);
context.put("tags", Arrays.asList("java", "spring", "mysql"));
Map<String, Object> user = new HashMap<>();
user.put("id", 1001);
user.put("name", "李四");
user.put("email", "lisi@example.com");
context.put("user", user);
}
@Test
public void testSimpleArithmetic() {
// 算术运算
assertEquals(30, simpleEvaluator.evaluate("age + 5", context));
assertEquals(20, simpleEvaluator.evaluate("age - 5", context));
assertEquals(50, simpleEvaluator.evaluate("age * 2", context));
assertEquals(12.5, simpleEvaluator.evaluate("age / 2", context));
assertEquals(1, simpleEvaluator.evaluate("age % 3", context));
// 复合运算
assertEquals(95.5, simpleEvaluator.evaluate("score + age / 2.5", context));
}
@Test
public void testSimpleComparison() {
// 比较运算
assertTrue(simpleEvaluator.evaluateBoolean("age > 18", context));
assertFalse(simpleEvaluator.evaluateBoolean("age < 18", context));
assertTrue(simpleEvaluator.evaluateBoolean("age >= 25", context));
assertTrue(simpleEvaluator.evaluateBoolean("age <= 25", context));
assertTrue(simpleEvaluator.evaluateBoolean("age == 25", context));
assertFalse(simpleEvaluator.evaluateBoolean("age != 25", context));
}
@Test
public void testSimpleLogical() {
// 逻辑运算
assertTrue(simpleEvaluator.evaluateBoolean("age > 18 && active", context));
assertTrue(simpleEvaluator.evaluateBoolean("age < 18 || active", context));
assertFalse(simpleEvaluator.evaluateBoolean("!active", context));
// 复合逻辑
assertTrue(simpleEvaluator.evaluateBoolean(
"(age > 18 && score > 80) || name == '张三'", context));
}
@Test
public void testSimpleFunctions() {
// 字符串函数
assertEquals(2, simpleEvaluator.evaluate("length(name)", context));
assertEquals("张三", simpleEvaluator.evaluate("upper(name)", context));
assertEquals("张三", simpleEvaluator.evaluate("lower(name)", context));
// 数学函数
assertEquals(25.0, simpleEvaluator.evaluate("abs(age)", context));
assertEquals(85.5, simpleEvaluator.evaluate("max(age, score)", context));
assertEquals(25.0, simpleEvaluator.evaluate("min(age, score)", context));
// 类型转换函数
assertEquals("25", simpleEvaluator.evaluate("toString(age)", context));
assertEquals(85, simpleEvaluator.evaluate("toInt(score)", context));
// 条件函数
assertEquals("成年", simpleEvaluator.evaluate(
"if(age >= 18, '成年', '未成年')", context));
}
@Test
public void testPropertyAccess() {
// 属性访问
assertEquals(1001, simpleEvaluator.evaluate("user.id", context));
assertEquals("李四", simpleEvaluator.evaluate("user.name", context));
assertEquals("lisi@example.com", simpleEvaluator.evaluate("user.email", context));
// 数组/列表访问
assertEquals("java", simpleEvaluator.evaluate("tags[0]", context));
assertEquals("spring", simpleEvaluator.evaluate("tags[1]", context));
assertEquals(3, simpleEvaluator.evaluate("size(tags)", context));
}
@Test
public void testScriptEvaluation() {
// JavaScript脚本
assertEquals(30, scriptEvaluator.evaluate(
"javascript: age + 5", context));
assertEquals("张三-25", scriptEvaluator.evaluate(
"javascript: name + '-' + age", context));
// 复杂脚本
String script = "javascript: " +
"var result = 0; " +
"for (var i = 0; i < age; i++) { " +
" result += i; " +
"} " +
"result;";
assertEquals(300, scriptEvaluator.evaluate(script, context)); // 0+1+2+...+24 = 300
// Groovy脚本
if (scriptEvaluator.getSupportedFunctions().contains("groovy")) {
assertEquals("Hello 张三!", scriptEvaluator.evaluate(
"groovy: 'Hello ' + name + '!'", context));
}
}
@Test
public void testExpressionCompilation() {
// 编译简单表达式
Expression expr1 = simpleEvaluator.compile("age * 2 + score");
assertEquals(135.5, expr1.execute(context));
// 编译脚本表达式
Expression expr2 = scriptEvaluator.compile("javascript: Math.max(age, score)");
assertEquals(85.5, expr2.execute(context));
}
@Test
public void testExpressionValidation() {
// 有效表达式
ValidationResult valid = simpleEvaluator.validate("age + score");
assertTrue(valid.isValid());
// 无效表达式
ValidationResult invalid = simpleEvaluator.validate("age +");
assertFalse(invalid.isValid());
assertNotNull(invalid.getErrorMessage());
}
@Test
public void testCustomFunctions() {
// 注册自定义函数
simpleEvaluator.registerFunction("double", args ->
((Number) args[0]).doubleValue() * 2);
assertEquals(50.0, simpleEvaluator.evaluate("double(age)", context));
// 注册复杂函数
simpleEvaluator.registerFunction("formatUser", args -> {
String name = args[0].toString();
int age = ((Number) args[1]).intValue();
return String.format("%s(%d岁)", name, age);
});
assertEquals("张三(25岁)", simpleEvaluator.evaluate(
"formatUser(name, age)", context));
}
@Test
public void testSecurityRestrictions() {
// 测试安全限制
try {
scriptEvaluator.evaluate(
"javascript: java.lang.System.exit(0)", context);
fail("应该抛出安全异常");
} catch (ExpressionEvaluationException e) {
assertTrue(e.getCause() instanceof SecurityException);
}
try {
scriptEvaluator.evaluate(
"javascript: new java.io.File('/etc/passwd')", context);
fail("应该抛出安全异常");
} catch (ExpressionEvaluationException e) {
assertTrue(e.getCause() instanceof SecurityException);
}
}
@Test
public void testPerformance() {
// 性能测试
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
simpleEvaluator.evaluate("age * 2 + score - 10", context);
}
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("1000次简单表达式评估耗时: " + duration + "ms");
assertTrue("性能测试失败,耗时过长", duration < 1000); // 应该在1秒内完成
}
}
🎯 设计亮点
1. 🏗️ 分层架构设计
- 接口层: 统一的表达式评估接口
- 解析层: 灵活的语法解析和AST构建
- 执行层: 多种执行引擎支持
- 函数层: 丰富的内置函数库
- 安全层: 完善的安全控制机制
2. 🔧 多引擎支持
- SimpleExpressionEvaluator: 轻量级,适合简单表达式
- ScriptExpressionEvaluator: 功能强大,支持多种脚本语言
- SpELExpressionEvaluator: 集成Spring表达式语言
- GroovyExpressionEvaluator: 支持Groovy动态语言
3. 🛡️ 安全机制
- 沙箱执行: 限制危险操作
- 资源控制: 防止资源耗尽
- 超时保护: 避免无限循环
- 权限检查: 细粒度的安全控制
4. ⚡ 性能优化
- 表达式编译: 预编译提高执行效率
- 结果缓存: 避免重复计算
- 惰性求值: 按需计算表达式
- 并发安全: 支持多线程环境
📚 本章小结
在本章中,我们实现了一个功能强大且安全的表达式引擎:
- 🎯 核心功能: 支持算术、逻辑、比较运算和函数调用
- 🔧 多语言支持: JavaScript、Groovy、Kotlin等脚本语言
- 🛡️ 安全保障: 沙箱执行和资源限制
- ⚡ 高性能: 表达式编译和缓存优化
- 🔌 可扩展: 自定义函数和运算符支持
表达式引擎为流程编排提供了强大的动态计算能力,使得条件判断、数据转换和业务逻辑变得更加灵活和强大。
下一章预告: 我们将探讨YAML配置解析器的实现,让流程定义更加直观和易于维护。 🚀