06 - 表达式引擎实现 🔍

🎯 目标: 设计灵活强大的表达式引擎,支持条件判断、数据计算和动态脚本执行

🤔 为什么需要表达式引擎?

在流程编排中,表达式引擎是实现动态逻辑的核心:

  • 🔀 条件判断: 根据运行时数据决定流程走向
  • 🧮 数据计算: 对上下文数据进行复杂计算
  • 🔄 循环控制: 动态确定循环的继续条件
  • 📊 数据转换: 在步骤间转换和映射数据
  • 🛡️ 安全执行: 在受控环境中执行用户代码

🏗️ 表达式引擎架构

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. ⚡ 性能优化

  • 表达式编译: 预编译提高执行效率
  • 结果缓存: 避免重复计算
  • 惰性求值: 按需计算表达式
  • 并发安全: 支持多线程环境

📚 本章小结

在本章中,我们实现了一个功能强大且安全的表达式引擎:

  1. 🎯 核心功能: 支持算术、逻辑、比较运算和函数调用
  2. 🔧 多语言支持: JavaScript、Groovy、Kotlin等脚本语言
  3. 🛡️ 安全保障: 沙箱执行和资源限制
  4. ⚡ 高性能: 表达式编译和缓存优化
  5. 🔌 可扩展: 自定义函数和运算符支持

表达式引擎为流程编排提供了强大的动态计算能力,使得条件判断、数据转换和业务逻辑变得更加灵活和强大。

下一章预告: 我们将探讨YAML配置解析器的实现,让流程定义更加直观和易于维护。 🚀

相关推荐
石小石Orz14 分钟前
效率提升一倍!谈谈我的高效开发工具链
前端·后端·trae
孟永峰_Java1 小时前
凌晨线上崩盘:NoClassDefFoundError血案纪实!日志里这行「小字」才是救世主
后端·代码规范
whitepure1 小时前
万字详解Java中的IO及序列化
java·后端
大得3692 小时前
django生成迁移文件,执行生成到数据库
后端·python·django
寻月隐君2 小时前
Rust Web 开发实战:使用 SQLx 连接 PostgreSQL 数据库
后端·rust·github
RainbowSea2 小时前
伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 06
java·spring boot·后端
Keya2 小时前
MacOS端口被占用的解决方法
前端·后端·设计模式
用户9096783069432 小时前
Python 判断一个字符串中是否含有数字
后端
jakeswang2 小时前
应用缓存不止是Redis!——亿级流量系统架构设计系列
redis·分布式·后端·缓存
RainbowSea2 小时前
伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 05
vue.js·spring boot·后端