This is an automated email from the ASF dual-hosted git repository.

zhaoqingran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git


The following commit(s) were added to refs/heads/master by this push:
     new 6c35f57b2 [improve] use apache jexl replace of aviator (#1859)
6c35f57b2 is described below

commit 6c35f57b2edb28b4b2bcfa0a0ac875e32454065a
Author: tomsun28 <[email protected]>
AuthorDate: Sat Apr 27 12:16:38 2024 +0800

    [improve] use apache jexl replace of aviator (#1859)
---
 README.md                                          |   2 +-
 README_CN.md                                       |   2 +-
 .../hertzbeat/alert/calculate/CalculateAlarm.java  |  38 +-
 .../alert/service/impl/AlertDefineServiceImpl.java |   4 +-
 .../collector/dispatch/MetricsCollect.java         |  71 +--
 common/pom.xml                                     |  10 +-
 .../common/config/AviatorConfiguration.java        | 200 --------
 .../hertzbeat/common/entity/job/Metrics.java       |   1 -
 .../hertzbeat/common/util/JexlCommonFunction.java  |  98 ++++
 .../common/util/JexlExpressionRunner.java          |  70 +++
 .../common/config/AviatorConfigurationTest.java    | 134 -----
 .../org/apache/hertzbeat/common/util/JexlTest.java | 565 +++++++++++++++++++++
 .../current/help/alert_threshold_expr.md           |   2 +-
 .../org/apache/hertzbeat/manager/ManagerTest.java  |   8 +-
 material/licenses/backend/LICENSE                  |  11 +-
 material/licenses/backend/LICENSE-aviator.txt      | 165 ------
 pom.xml                                            |  14 +-
 17 files changed, 808 insertions(+), 587 deletions(-)

diff --git a/README.md b/README.md
index 649ec2046..90589b164 100644
--- a/README.md
+++ b/README.md
@@ -466,7 +466,7 @@ WeChat Public : Search `Apache HertzBeat` or `usthecom`.
 
 HertzBeat is built on so many great open source projects, thanks to them!
 
-- `Java Spring SpringBoot Jpa Maven Assembly Netty Lombok Sureness Aviator 
Protobuf HttpClient Guava SnakeYaml JsonPath ...`
+- `Java Spring SpringBoot Jpa Maven Assembly Netty Lombok Sureness Protobuf 
HttpClient Guava SnakeYaml JsonPath ...`
 - `TypeScript Angular NG-ZORRO NG-ALAIN NodeJs Npm Html Less Echarts Rxjs 
ZoneJs MonacoEditor SlickCarousel Docusaurus ...`
 
 ## Landscape
diff --git a/README_CN.md b/README_CN.md
index a894b2098..b159b4039 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -466,7 +466,7 @@ Thanks these wonderful people, welcome to join us:
 
 HertzBeat is built on so many great open source projects, thanks to them!
 
-- `Java Spring SpringBoot Jpa Maven Assembly Netty Lombok Sureness Aviator 
Protobuf HttpClient Guava SnakeYaml JsonPath ...`
+- `Java Spring SpringBoot Jpa Maven Assembly Netty Lombok Sureness Protobuf 
HttpClient Guava SnakeYaml JsonPath ...`
 - `TypeScript Angular NG-ZORRO NG-ALAIN NodeJs Npm Html Less Echarts Rxjs 
ZoneJs MonacoEditor SlickCarousel Docusaurus ...`
 
 
diff --git 
a/alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CalculateAlarm.java
 
b/alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CalculateAlarm.java
index f18738b3c..fb60f50f8 100644
--- 
a/alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CalculateAlarm.java
+++ 
b/alerter/src/main/java/org/apache/hertzbeat/alert/calculate/CalculateAlarm.java
@@ -26,11 +26,6 @@ import static 
org.apache.hertzbeat.common.constants.CommonConstants.TAG_METRICS;
 import static 
org.apache.hertzbeat.common.constants.CommonConstants.TAG_MONITOR_APP;
 import static 
org.apache.hertzbeat.common.constants.CommonConstants.TAG_MONITOR_ID;
 import static 
org.apache.hertzbeat.common.constants.CommonConstants.TAG_MONITOR_NAME;
-import com.googlecode.aviator.AviatorEvaluator;
-import com.googlecode.aviator.Expression;
-import com.googlecode.aviator.exception.CompileExpressionErrorException;
-import com.googlecode.aviator.exception.ExpressionRuntimeException;
-import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
 import jakarta.persistence.criteria.Predicate;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -40,6 +35,8 @@ import java.util.ResourceBundle;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlExpression;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.hertzbeat.alert.AlerterWorkerPool;
 import org.apache.hertzbeat.alert.dao.AlertMonitorDao;
@@ -57,6 +54,7 @@ import org.apache.hertzbeat.common.queue.CommonDataQueue;
 import org.apache.hertzbeat.common.support.event.MonitorDeletedEvent;
 import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
 import org.apache.hertzbeat.common.util.CommonUtil;
+import org.apache.hertzbeat.common.util.JexlExpressionRunner;
 import org.apache.hertzbeat.common.util.ResourceBundleUtil;
 import org.springframework.context.event.EventListener;
 import org.springframework.data.jpa.domain.Specification;
@@ -321,22 +319,24 @@ public class CalculateAlarm {
 
     private boolean execAlertExpression(Map<String, Object> fieldValueMap, 
String expr) {
         Boolean match;
+        JexlExpression expression;
         try {
-            Expression expression = AviatorEvaluator.compile(expr, true);
-            expression.getVariableNames().forEach(variable -> {
-                if (!fieldValueMap.containsKey(variable)) {
-                    throw new ExpressionRuntimeException("metrics value not 
contains expr field: " + variable);
-                }
-            });
-            match = (Boolean) expression.execute(fieldValueMap);
-        } catch (CompileExpressionErrorException | 
ExpressionSyntaxErrorException compileException) {
-            log.error("Alert Define Rule: {} Compile Error: {}.", expr, 
compileException.getMessage());
-            throw compileException;
-        } catch (ExpressionRuntimeException expressionRuntimeException) {
-            log.error("Alert Define Rule: {} Run Error: {}.", expr, 
expressionRuntimeException.getMessage());
-            throw expressionRuntimeException;
+            expression = JexlExpressionRunner.compile(expr);
+        } catch (JexlException jexlException) {
+            log.error("Alarm Rule: {} Compile Error: {}.", expr, 
jexlException.getMessage());
+            throw jexlException;
+        } catch (Exception e) {
+            log.error("Alarm Rule: {} Unknown Error: {}.", expr, 
e.getMessage());
+            throw e;
+        }
+
+        try {
+            match = (Boolean) JexlExpressionRunner.evaluate(expression, 
fieldValueMap);
+        } catch (JexlException jexlException) {
+            log.error("Alarm Rule: {} Run Error: {}.", expr, 
jexlException.getMessage());
+            throw jexlException;
         } catch (Exception e) {
-            log.error("Alert Define Rule: {} Unknown Error: {}.", expr, 
e.getMessage());
+            log.error("Alarm Rule: {} Unknown Error: {}.", expr, 
e.getMessage());
             throw e;
         }
         return match != null && match;
diff --git 
a/alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlertDefineServiceImpl.java
 
b/alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlertDefineServiceImpl.java
index b66ef9841..21d07b2e1 100644
--- 
a/alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlertDefineServiceImpl.java
+++ 
b/alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/AlertDefineServiceImpl.java
@@ -17,7 +17,6 @@
 
 package org.apache.hertzbeat.alert.service.impl;
 
-import com.googlecode.aviator.AviatorEvaluator;
 import jakarta.servlet.http.HttpServletResponse;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
@@ -35,6 +34,7 @@ import 
org.apache.hertzbeat.alert.service.AlertDefineImExportService;
 import org.apache.hertzbeat.alert.service.AlertDefineService;
 import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
 import org.apache.hertzbeat.common.entity.alerter.AlertDefineMonitorBind;
+import org.apache.hertzbeat.common.util.JexlExpressionRunner;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
@@ -70,7 +70,7 @@ public class AlertDefineServiceImpl implements 
AlertDefineService {
         // todo
         if (StringUtils.hasText(alertDefine.getExpr())) {
             try {
-                AviatorEvaluator.compile(alertDefine.getExpr(), false);
+                JexlExpressionRunner.compile(alertDefine.getExpr());
             } catch (Exception e) {
                 throw new IllegalArgumentException("alert expr error: " + 
e.getMessage());
             }
diff --git 
a/collector/src/main/java/org/apache/hertzbeat/collector/dispatch/MetricsCollect.java
 
b/collector/src/main/java/org/apache/hertzbeat/collector/dispatch/MetricsCollect.java
index a32005499..f5b54556f 100644
--- 
a/collector/src/main/java/org/apache/hertzbeat/collector/dispatch/MetricsCollect.java
+++ 
b/collector/src/main/java/org/apache/hertzbeat/collector/dispatch/MetricsCollect.java
@@ -17,8 +17,6 @@
 
 package org.apache.hertzbeat.collector.dispatch;
 
-import com.googlecode.aviator.AviatorEvaluator;
-import com.googlecode.aviator.Expression;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -28,6 +26,7 @@ import java.util.Objects;
 import java.util.stream.Collectors;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.jexl3.JexlExpression;
 import org.apache.hertzbeat.collector.collect.AbstractCollect;
 import 
org.apache.hertzbeat.collector.collect.prometheus.PrometheusAutoCollectImpl;
 import org.apache.hertzbeat.collector.collect.strategy.CollectStrategyFactory;
@@ -40,6 +39,7 @@ import org.apache.hertzbeat.common.entity.job.Job;
 import org.apache.hertzbeat.common.entity.job.Metrics;
 import org.apache.hertzbeat.common.entity.message.CollectRep;
 import org.apache.hertzbeat.common.util.CommonUtil;
+import org.apache.hertzbeat.common.util.JexlExpressionRunner;
 import org.apache.hertzbeat.common.util.Pair;
 
 /**
@@ -203,11 +203,11 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
         }
         // eg: database_pages=Database pages unconventional mapping 
         Map<String, String> fieldAliasMap = new HashMap<>(8);
-        Map<String, Expression> fieldExpressionMap = metrics.getCalculates()
+        Map<String, JexlExpression> fieldExpressionMap = 
metrics.getCalculates()
                 .stream()
                 .map(cal -> transformCal(cal, fieldAliasMap))
                 .filter(Objects::nonNull)
-                .collect(Collectors.toMap(arr -> (String) arr[0], arr -> 
(Expression) arr[1], (oldValue, newValue) -> newValue));
+                .collect(Collectors.toMap(arr -> (String) arr[0], arr -> 
(JexlExpression) arr[1], (oldValue, newValue) -> newValue));
 
         if (metrics.getUnits() == null) {
             metrics.setUnits(Collections.emptyList());
@@ -220,46 +220,47 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
 
         List<Metrics.Field> fields = metrics.getFields();
         List<String> aliasFields = metrics.getAliasFields();
-        Map<String, String> aliasFieldValueMap = new HashMap<>(16);
-        Map<String, Object> fieldValueMap = new HashMap<>(16);
+        Map<String, String> aliasFieldValueMap = new HashMap<>(8);
+        Map<String, Object> fieldValueMap = new HashMap<>(8);
+        Map<String, String> aliasFieldUnitMap = new HashMap<>(8);
         CollectRep.ValueRow.Builder realValueRowBuilder = 
CollectRep.ValueRow.newBuilder();
         for (CollectRep.ValueRow aliasRow : aliasRowList) {
             for (int aliasIndex = 0; aliasIndex < aliasFields.size(); 
aliasIndex++) {
                 String aliasFieldValue = aliasRow.getColumns(aliasIndex);
+                String aliasField = aliasFields.get(aliasIndex);
                 if (!CommonConstants.NULL_VALUE.equals(aliasFieldValue)) {
-                    aliasFieldValueMap.put(aliasFields.get(aliasIndex), 
aliasFieldValue);
+                    aliasFieldValueMap.put(aliasField, aliasFieldValue);
+                    // whether the alias field is a number
+                    CollectUtil.DoubleAndUnit doubleAndUnit = CollectUtil
+                            .extractDoubleAndUnitFromStr(aliasFieldValue);
+                    if (doubleAndUnit != null) {
+                        fieldValueMap.put(aliasField, 
doubleAndUnit.getValue());
+                        if (doubleAndUnit.getUnit() != null) {
+                            aliasFieldUnitMap.put(aliasField, 
doubleAndUnit.getUnit());
+                        }
+                    } else {
+                        fieldValueMap.put(aliasField, aliasFieldValue);
+                    }
+                } else {
+                    fieldValueMap.put(aliasField, null);
                 }
             }
 
             for (Metrics.Field field : fields) {
                 String realField = field.getField();
-                Expression expression = fieldExpressionMap.get(realField);
+                JexlExpression expression = fieldExpressionMap.get(realField);
                 String value = null;
                 String aliasFieldUnit = null;
                 if (expression != null) {
-                    // If there is a calculation expression, calculate the 
value
-                    if (CommonConstants.TYPE_NUMBER == field.getType()) {
-                        for (String variable : 
expression.getVariableFullNames()) {
-                            // extract double value and unit from aliasField 
value
-                            CollectUtil.DoubleAndUnit doubleAndUnit = 
CollectUtil
-                                    
.extractDoubleAndUnitFromStr(aliasFieldValueMap.get(variable));
-                            if (doubleAndUnit != null) {
-                                Double doubleValue = doubleAndUnit.getValue();
-                                aliasFieldUnit = doubleAndUnit.getUnit();
-                                fieldValueMap.put(variable, doubleValue);
-                            } else {
-                                fieldValueMap.put(variable, null);
+                    try {
+                        for (Map.Entry<String, String> unitEntry : 
aliasFieldUnitMap.entrySet()) {
+                            if 
(expression.getSourceText().contains(unitEntry.getKey())) {
+                                aliasFieldUnit = unitEntry.getValue();
+                                break;
                             }
                         }
-                    } else {
-                        for (String variable : 
expression.getVariableFullNames()) {
-                            String strValue = aliasFieldValueMap.get(variable);
-                            fieldValueMap.put(variable, strValue);
-                        }
-                    }
-                    try {
                         // valueList为空时也执行,涵盖纯字符串赋值表达式
-                        Object objValue = expression.execute(fieldValueMap);
+                        Object objValue = 
JexlExpressionRunner.evaluate(expression, fieldValueMap);
                         if (objValue != null) {
                             value = String.valueOf(objValue);
                         }
@@ -274,16 +275,15 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
                     } else {
                         value = aliasFieldValueMap.get(realField);
                     }
-
+                    
                     if (value != null) {
                         final byte fieldType = field.getType();
-
                         if (fieldType == CommonConstants.TYPE_NUMBER) {
                             CollectUtil.DoubleAndUnit doubleAndUnit = 
CollectUtil
                                     .extractDoubleAndUnitFromStr(value);
-                            final Double tempValue = doubleAndUnit.getValue();
+                            final Double tempValue = doubleAndUnit == null ? 
null : doubleAndUnit.getValue();
                             value = tempValue == null ? null : 
String.valueOf(tempValue);
-                            aliasFieldUnit = doubleAndUnit.getUnit();
+                            aliasFieldUnit = doubleAndUnit == null ? null : 
doubleAndUnit.getUnit();
                         } else if (fieldType == CommonConstants.TYPE_TIME) {
                             final int tempValue;
                             value = (tempValue = 
CommonUtil.parseTimeStrToSecond(value)) == -1 ? null : 
String.valueOf(tempValue);
@@ -314,9 +314,10 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
                     value = CommonConstants.NULL_VALUE;
                 }
                 realValueRowBuilder.addColumns(value);
-                fieldValueMap.clear();
             }
             aliasFieldValueMap.clear();
+            fieldValueMap.clear();
+            aliasFieldUnitMap.clear();
             collectData.addValues(realValueRowBuilder.build());
             realValueRowBuilder.clear();
         }
@@ -332,9 +333,9 @@ public class MetricsCollect implements Runnable, 
Comparable<MetricsCollect> {
         int splitIndex = cal.indexOf("=");
         String field = cal.substring(0, splitIndex).trim();
         String expressionStr = cal.substring(splitIndex + 
1).trim().replace("\\#", "#");
-        Expression expression;
+        JexlExpression expression;
         try {
-            expression = AviatorEvaluator.compile(expressionStr, true);
+            expression = JexlExpressionRunner.compile(expressionStr);
         } catch (Exception e) {
             fieldAliasMap.put(field, expressionStr);
             return null;
diff --git a/common/pom.xml b/common/pom.xml
index 20b6683ce..add11f7c3 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -78,11 +78,6 @@
             <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
             <scope>provided</scope>
         </dependency>
-        <!-- Expression evaluation -->
-        <dependency>
-            <groupId>com.googlecode.aviator</groupId>
-            <artifactId>aviator</artifactId>
-        </dependency>
         <!-- Tool dependencies  -->
         <dependency>
             <groupId>com.google.guava</groupId>
@@ -120,6 +115,11 @@
             <groupId>org.apache.kafka</groupId>
             <artifactId>kafka-clients</artifactId>
         </dependency>
+        <!-- expr calculate -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-jexl3</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.commons</groupId>
diff --git 
a/common/src/main/java/org/apache/hertzbeat/common/config/AviatorConfiguration.java
 
b/common/src/main/java/org/apache/hertzbeat/common/config/AviatorConfiguration.java
deleted file mode 100644
index c690ef0f0..000000000
--- 
a/common/src/main/java/org/apache/hertzbeat/common/config/AviatorConfiguration.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hertzbeat.common.config;
-
-import com.googlecode.aviator.AviatorEvaluator;
-import com.googlecode.aviator.AviatorEvaluatorInstance;
-import com.googlecode.aviator.Feature;
-import com.googlecode.aviator.Options;
-import com.googlecode.aviator.lexer.token.OperatorType;
-import com.googlecode.aviator.runtime.function.AbstractFunction;
-import com.googlecode.aviator.runtime.type.AviatorBoolean;
-import com.googlecode.aviator.runtime.type.AviatorDouble;
-import com.googlecode.aviator.runtime.type.AviatorObject;
-import com.googlecode.aviator.runtime.type.AviatorString;
-import com.googlecode.aviator.runtime.type.AviatorType;
-import java.util.Map;
-import java.util.Objects;
-import java.util.regex.Pattern;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-
-/**
- * aviator config
- */
-@Configuration
-@Slf4j
-public class AviatorConfiguration {
-
-    private static final int AVIATOR_LRU_CACHE_SIZE = 1024;
-
-    @Bean
-    public AviatorEvaluatorInstance configAviatorEvaluator() {
-        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
-
-        // Configure AviatorEvaluator to cache compiled expressions using LRU
-        instance
-                .useLRUExpressionCache(AVIATOR_LRU_CACHE_SIZE)
-                .addFunction(new StrEqualFunction());
-
-        // limit loop Limit the number of loops
-        instance.setOption(Options.MAX_LOOP_COUNT, 10);
-        
-        // Enables a partial Aviator syntax feature collection
-        instance.setOption(Options.FEATURE_SET,
-                Feature.asSet(Feature.If,
-                        Feature.Assignment,
-                        Feature.Let,
-                        Feature.StringInterpolation));
-
-        // Configure the custom aviator function
-        instance.addOpFunction(OperatorType.BIT_OR, new AbstractFunction() {
-            @Override
-            public AviatorObject call(final Map<String, Object> env, final 
AviatorObject arg1,
-                                      final AviatorObject arg2) {
-                try {
-                    Object value1 = arg1.getValue(env);
-                    Object value2 = arg2.getValue(env);
-                    Object currentValue = value1 == null ? value2 : value1;
-                    if (arg1.getAviatorType() == AviatorType.String) {
-                        return new AviatorString(String.valueOf(currentValue));
-                    } else {
-                        return AviatorDouble.valueOf(currentValue);
-                    }
-                } catch (Exception e) {
-                    log.error(e.getMessage());
-                }
-                return arg1.bitOr(arg2, env);
-            }
-            
-            @Override
-            public String getName() {
-                return OperatorType.BIT_OR.getToken();
-            }
-        });
-
-        instance.addFunction(new StrContainsFunction());
-        instance.addFunction(new ObjectExistsFunction());
-        instance.addFunction(new StrMatchesFunction());
-        return instance;
-    }
-
-    /**
-     * Define a custom aviator string equality function
-     */
-    private static class StrEqualFunction extends AbstractFunction {
-        @Override
-        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, 
AviatorObject arg2) {
-            if (arg1 == null || arg2 == null) {
-                return AviatorBoolean.FALSE;
-            }
-            Object leftTmp = arg1.getValue(env);
-            Object rightTmp = arg2.getValue(env);
-            if (leftTmp == null || rightTmp == null) {
-                return AviatorBoolean.FALSE;
-            }
-            String left = String.valueOf(leftTmp);
-            String right = String.valueOf(rightTmp);
-            return AviatorBoolean.valueOf(left.equalsIgnoreCase(right));
-        }
-        
-        @Override
-        public String getName() {
-            return "equals";
-        }
-    }
-
-    /**
-     * Custom aviator determines whether string 1 contains string 2 
(case-insensitive)
-     */
-    private static class StrContainsFunction extends AbstractFunction {
-        @Override
-        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, 
AviatorObject arg2) {
-            if (arg1 == null || arg2 == null) {
-                return AviatorBoolean.FALSE;
-            }
-            Object leftTmp = arg1.getValue(env);
-            Object rightTmp = arg2.getValue(env);
-            if (leftTmp == null || rightTmp == null) {
-                return AviatorBoolean.FALSE;
-            }
-            String left = String.valueOf(leftTmp);
-            String right = String.valueOf(rightTmp);
-            return AviatorBoolean.valueOf(StringUtils.containsIgnoreCase(left, 
right));
-        }
-        
-        @Override
-        public String getName() {
-            return "contains";
-        }
-    }
-
-    /**
-     * Custom aviator determines if a value exists for this object in the 
environment
-     */
-    private static class ObjectExistsFunction extends AbstractFunction {
-        @Override
-        public AviatorObject call(Map<String, Object> env, AviatorObject arg) {
-            if (arg == null) {
-                return AviatorBoolean.FALSE;
-            }
-            Object keyTmp = arg.getValue(env);
-            if (Objects.isNull(keyTmp)) {
-                return AviatorBoolean.FALSE;
-            } else {
-                String key = String.valueOf(keyTmp);
-                return AviatorBoolean.valueOf(StringUtils.isNotEmpty(key));
-            }
-        }
-        
-        @Override
-        public String getName() {
-            return "exists";
-        }
-    }
-
-    /**
-     * Custom aviator determines if a string matches a regex
-     * - regex You need to add "" or ''
-     */
-    private static class StrMatchesFunction extends AbstractFunction {
-        @Override
-        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, 
AviatorObject arg2) {
-            if (arg1 == null || arg2 == null) {
-                return AviatorBoolean.FALSE;
-            }
-            Object strTmp = arg1.getValue(env);
-            Object regexTmp = arg2.getValue(env);
-            if (strTmp == null || regexTmp == null) {
-                return AviatorBoolean.FALSE;
-            }
-            String str = String.valueOf(strTmp);
-            String regex = String.valueOf(regexTmp);
-            boolean isMatch = Pattern.compile(regex).matcher(str).matches();
-            return AviatorBoolean.valueOf(isMatch);
-        }
-        
-        @Override
-        public String getName() {
-            return "matches";
-        }
-    }
-}
diff --git 
a/common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java 
b/common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java
index 6bb96574e..1e517fd90 100644
--- a/common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java
+++ b/common/src/main/java/org/apache/hertzbeat/common/entity/job/Metrics.java
@@ -102,7 +102,6 @@ public class Metrics {
      * Public attribute - expression calculation, map the pre-query attribute 
(pre Fields)
      * with the final attribute (fields), and calculate the final attribute 
(fields) value
      * eg: size = size1 + size2, speed = speedSize
-     * <a 
href="https://www.yuque.com/boyan-avfmj/aviatorscript/ban32m";>www.yuque.com/boyan-avfmj/aviatorscript/ban32m</a>
      */
     private List<String> calculates;
     /**
diff --git 
a/common/src/main/java/org/apache/hertzbeat/common/util/JexlCommonFunction.java 
b/common/src/main/java/org/apache/hertzbeat/common/util/JexlCommonFunction.java
new file mode 100644
index 000000000..7ccdced22
--- /dev/null
+++ 
b/common/src/main/java/org/apache/hertzbeat/common/util/JexlCommonFunction.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hertzbeat.common.util;
+
+import java.util.regex.Pattern;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * the common function for jexl str equals, match, contains, etc.
+ * sys:now() 
+ */
+@Data
+public class JexlCommonFunction {
+
+    /**
+     * Get the current time in milliseconds
+     * @return current time
+     */
+    public long now() {
+        return System.currentTimeMillis();
+    }
+
+
+    /**
+     * Define a custom string equality function
+     * @param left left
+     * @param right right
+     * @return true if equals
+     */
+    public boolean equals(String left, String right) {
+        if (left == null && right == null) {
+            return true;
+        }
+        if (left == null || right == null) {
+            return false;
+        }
+        return left.equals(right);
+    }
+
+    /**
+     * Custom determines whether string 1 contains string 2 (case-insensitive)
+     * @param left left
+     * @param right right
+     * @return true if contains
+     */
+    public boolean contains(String left, String right) {
+        if (left == null || right == null) {
+            return false;
+        }
+        return StringUtils.containsIgnoreCase(left, right);
+    }
+
+
+    /**
+     * Custom determines if a value exists for this object in the environment
+     * @param arg arg
+     * @return true if exists
+     */
+    public boolean exists(Object arg) {
+        if (arg == null) {
+            return false;
+        }
+        return StringUtils.isNotEmpty(String.valueOf(arg));
+    }
+
+    /**
+     * Custom determines if a string matches a regex
+     * - regex You need to add "" or ''
+     * @param str str
+     * @param regex regex
+     * @return true if matches
+     */
+    public boolean matches(String str, String regex) {
+        if (str == null || regex == null) {
+            return false;
+        }
+        return Pattern.compile(regex).matcher(str).matches();
+    }
+    
+}
diff --git 
a/common/src/main/java/org/apache/hertzbeat/common/util/JexlExpressionRunner.java
 
b/common/src/main/java/org/apache/hertzbeat/common/util/JexlExpressionRunner.java
new file mode 100644
index 000000000..6d13886ea
--- /dev/null
+++ 
b/common/src/main/java/org/apache/hertzbeat/common/util/JexlExpressionRunner.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hertzbeat.common.util;
+
+import com.google.common.collect.Maps;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlExpression;
+import org.apache.commons.jexl3.MapContext;
+
+/**
+ * jexl express runner
+ */
+public class JexlExpressionRunner {
+
+    private static final JexlEngine jexlEngine;
+    
+    static {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        // set the root namespace function
+        functions.put(null, new JexlCommonFunction());
+        jexlEngine = new 
JexlBuilder().charset(StandardCharsets.UTF_8).cache(256)
+                .strict(true).silent(false).namespaces(functions).create();
+    }
+    
+    public static Object evaluate(String expression, Map<String, Object> 
context) {
+        JexlContext jexlContext = new MapContext();
+        for (Map.Entry<String, Object> entry : context.entrySet()) {
+            jexlContext.set(entry.getKey(), entry.getValue());
+        }
+        return jexlEngine.createExpression(expression).evaluate(jexlContext);
+    }
+
+    public static Object evaluate(JexlExpression expression, Map<String, 
Object> context) {
+        JexlContext jexlContext = new MapContext();
+        for (Map.Entry<String, Object> entry : context.entrySet()) {
+            jexlContext.set(entry.getKey(), entry.getValue());
+        }
+        return expression.evaluate(jexlContext);
+    }
+    
+    public static Object evaluate(String expression) {
+        return jexlEngine.createExpression(expression).evaluate(new 
MapContext());
+    }
+    
+    public static JexlExpression compile(String expression) {
+        return jexlEngine.createExpression(expression);
+    }
+    
+}
diff --git 
a/common/src/test/java/org/apache/hertzbeat/common/config/AviatorConfigurationTest.java
 
b/common/src/test/java/org/apache/hertzbeat/common/config/AviatorConfigurationTest.java
deleted file mode 100644
index 4ca9dda79..000000000
--- 
a/common/src/test/java/org/apache/hertzbeat/common/config/AviatorConfigurationTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hertzbeat.common.config;
-
-import com.googlecode.aviator.AviatorEvaluator;
-import com.googlecode.aviator.exception.UnsupportedFeatureException;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- *
- *
- */
-class AviatorConfigurationTest {
-
-    @BeforeAll
-    static void setUp() {
-        AviatorConfiguration aviatorConfig = new AviatorConfiguration();
-        aviatorConfig.configAviatorEvaluator();
-    }
-
-    @Test
-    void testCustomStringFunctions() {
-        Map<String, Object> env = new HashMap<>();
-        env.put("k1", "Intel");
-        env.put("k2", "intel");
-        env.put("k3", "Ubuntu 18.04.6 LTS");
-        env.put("k4", "ubuntu");
-        env.put("k5", "Ubntu");
-        env.put("k6", null);
-
-        // test StrEqualFunction
-        String expr1 = "equals(k1,k2)"; // case-insensitive
-        Boolean res1 = (Boolean) AviatorEvaluator.compile(expr1).execute(env);
-        Assertions.assertTrue(res1);
-
-        String expr2 = "equals(k1,k3)";
-        Boolean res2 = (Boolean) AviatorEvaluator.compile(expr2).execute(env);
-        Assertions.assertFalse(res2);
-
-        // test StrContainsFunction
-        String expr3 = "contains(k3,k4)"; // case-insensitive
-        Boolean res3 = (Boolean) AviatorEvaluator.compile(expr3).execute(env);
-        Assertions.assertTrue(res3);
-
-        String expr4 = "contains(k4,k3)";
-        Boolean res4 = (Boolean) AviatorEvaluator.compile(expr4).execute(env);
-        Assertions.assertFalse(res4);
-
-        String expr5 = "contains(k3,k5)"; // subsequence
-        Boolean res5 = (Boolean) AviatorEvaluator.compile(expr5).execute(env);
-        Assertions.assertFalse(res5);
-
-        // test StrExistsFunction
-        String expr6 = "exists('DNE_Key1')";
-        Boolean res6 = (Boolean) AviatorEvaluator.compile(expr6).execute(env);
-        Assertions.assertTrue(res6);
-
-        String expr7 = "exists(k6)";
-        Boolean res7 = (Boolean) AviatorEvaluator.compile(expr7).execute(env);
-        Assertions.assertFalse(res7);
-        
-        String expr21 = "exists('k5')";
-        Boolean res21 = (Boolean) 
AviatorEvaluator.compile(expr21).execute(env);
-        Assertions.assertTrue(res21);
-        
-        String expr22 = "exists(k5)";
-        Boolean res22 = (Boolean) 
AviatorEvaluator.compile(expr22).execute(env);
-        Assertions.assertTrue(res22);
-
-        // test StrMatchesFunction
-        String regex1 = "'^[a-zA-Z0-9]+$'"; // only alphanumeric
-        String expr8 = "matches(k6," + regex1 + ")";
-        env.put("k6", "Ubntu50681269");
-        Boolean res8 = (Boolean) AviatorEvaluator.compile(expr8).execute(env);
-        Assertions.assertTrue(res8);
-        env.put("k6", "Ubnt_u50681269");
-        Boolean res9 = (Boolean) AviatorEvaluator.compile(expr8).execute(env);
-        Assertions.assertFalse(res9);
-
-        String regex2 = "'^Ubuntu.*'"; // starts with
-        String expr9 = "matches(k3," + regex2 + ")";
-        Boolean res10 = (Boolean) AviatorEvaluator.compile(expr9).execute(env);
-        Assertions.assertTrue(res10);
-        env.put("k3", "Ubunt_u50681269");
-        Boolean res11 = (Boolean) AviatorEvaluator.compile(expr9).execute(env);
-        Assertions.assertFalse(res11);
-
-        String regex3 = "\"^\\\\[LOG\\\\].*error$\""; // starts & ends with
-        String expr10 = "matches(k7," + regex3 + ")";
-        env.put("k7", "[LOG] detected system error");
-        Boolean res12 = (Boolean) 
AviatorEvaluator.compile(expr10).execute(env);
-        Assertions.assertTrue(res12);
-        env.put("k7", "[LOG detected system error");
-        Boolean res13 = (Boolean) 
AviatorEvaluator.compile(expr10).execute(env);
-        Assertions.assertFalse(res13);
-    }
-
-    @Test
-    void testRCE() {
-        // test if 'new' syntax is disabled to prevent RCE
-        Assertions.assertThrows(UnsupportedFeatureException.class, () -> {
-            String expr1 = "let d = new java.util.Date();\n" +
-                    "p(type(d));\n" +
-                    "p(d);";
-            AviatorEvaluator.compile(expr1, true).execute();
-        });
-        // test allowed features
-        String expr2 = "let a = 0;\n" +
-                "if (\"#{a}\" == \"0\") { a = -1; }\n" +
-                "a == -1";
-        Boolean result = (Boolean) AviatorEvaluator.compile(expr2, 
true).execute();
-        Assertions.assertTrue(result);
-    }
-}
diff --git 
a/common/src/test/java/org/apache/hertzbeat/common/util/JexlTest.java 
b/common/src/test/java/org/apache/hertzbeat/common/util/JexlTest.java
new file mode 100644
index 000000000..4cf0f4233
--- /dev/null
+++ b/common/src/test/java/org/apache/hertzbeat/common/util/JexlTest.java
@@ -0,0 +1,565 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hertzbeat.common.util;
+
+import com.google.common.collect.Maps;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlExpression;
+import org.apache.commons.jexl3.MapContext;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * test case for java expression language
+ */
+public class JexlTest {
+
+    private JexlBuilder jexlBuilder;
+    
+    @BeforeEach
+    void setUp() {
+        jexlBuilder = new 
JexlBuilder().charset(StandardCharsets.UTF_8).cache(256)
+                .strict(true).silent(false);
+    }
+    
+    
+    @Test
+    void testMultiExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x * y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(8, o);
+    }
+    
+    @Test
+    void testDivisionExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x / y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(8, o);
+    }
+    
+    @Test
+    void testAdditionExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x + y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(9, o);
+        context.set("x", "hello");
+        context.set("y", 3.0);
+        e = jexl.createExpression("x + y");
+        o = e.evaluate(context);
+        Assertions.assertEquals("hello3.0", o);
+    }
+    
+    @Test
+    void testSubtractionExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x - y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(7, o);
+    }
+    
+    @Test
+    void testModulusExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 3);
+        JexlExpression e = jexl.createExpression("x % y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(2, o);
+    }
+    
+    @Test
+    void testComplicatedExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x * y + 2 * x - y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(23, o);
+    }
+    
+    @Test
+    void testComplicatedExpressionWithParentheses() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("(x * y) + (2 * x) - y");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(23, o);
+    }
+    
+    @Test
+    void testComplicatedExpressionWithParenthesesAndSpaces() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression(" ( x * y ) + ( 2 * x ) - y 
");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(23, o);
+    }
+    
+    @Test
+    void testComplicatedSpecialVariableNameExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x.y", 8);
+        context.set("y", 1);
+        context.set("$.os.cpu.load_average.1m", 23);
+        context.set("$.os.load_average", 55);
+        context.set("$.fs.total.total_in_bytes", 20.0);
+        JexlExpression e = jexl.createExpression("x.y * y + 2 * x.y - y + 
$.os.cpu.load_average.1m + $.os.load_average + $.fs.total.total_in_bytes");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(121.0, o);
+    }
+    
+    @Test
+    void 
testComplicatedSpecialVariableNameExpressionWithParenthesesAndSpaces() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x.y", 8);
+        context.set("y", 1);
+        context.set("$.os.cpu.load_average.1m", 23);
+        context.set("$.os.load_average", 55);
+        context.set("$.fs.total.total_in_bytes", 20.0);
+        JexlExpression e = jexl.createExpression(" ( x.y * y ) + ( 2 * x.y ) - 
y + $.os.cpu.load_average.1m + $.os.load_average + $.fs.total.total_in_bytes ");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(121.0, o);
+    }
+    
+    @Test
+    void testVariableAssignment() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("$.fs.total.total_in_bytes", 20.0);
+        JexlExpression e = jexl.createExpression(" $.fs.total.total_in_bytes 
");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(20.0, o);
+    }
+    
+    @Test
+    void testSpecialVariableNameWithoutSpacesExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("$.fs.total.free_in_bytes", 12.0);
+        context.set("$.fs.total.total_in_bytes", 23.0);
+        JexlExpression e = 
jexl.createExpression("(1-$.fs.total.free_in_bytes/$.fs.total.total_in_bytes)*100");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(47.82608695652174, o);
+    }
+
+    @Test
+    void testSpecialVariableNameWithSpacesExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("$.fs.total.free_in_bytes", 12.0);
+        context.set("$.fs.total.total_in_bytes", 23.0);
+        JexlExpression e = jexl.createExpression("( 1 - 
$.fs.total.free_in_bytes / $.fs.total.total_in_bytes ) * 100");
+        Object o = e.evaluate(context);
+        Assertions.assertEquals(47.82608695652174, o);
+    }
+    
+    @Test
+    void testJudgmentExpression() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("x > y");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithParentheses() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("(x > y)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithParenthesesAndSpaces() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression(" ( x > y ) ");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithAndOperator() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        context.set("z", 2);
+        JexlExpression e = jexl.createExpression("x > y && x < z");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithOrOperator() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        context.set("z", 2);
+        JexlExpression e = jexl.createExpression("x > y || x < z");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithNotOperator() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        JexlExpression e = jexl.createExpression("!(x == 8)");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testJudgmentExpressionWithNotOperatorAndParentheses() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("$.fs.total.free_in_bytes", 8);
+        JexlExpression e = jexl.createExpression("!($.fs.total.free_in_bytes 
== 8)");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+
+    @Test
+    void testCustomFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("date", new DateFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 1);
+        JexlExpression e = jexl.createExpression("date:now(x,y)");
+        Object o = e.evaluate(context);
+        String result = (String) o;
+        Assertions.assertTrue(result.endsWith("2"));
+    }
+    
+    @Test
+    void testZeroThrowException() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", 0);
+        JexlExpression e = jexl.createExpression("x / y");
+        Assertions.assertThrows(JexlException.class, () -> 
e.evaluate(context));
+    }
+    
+    @Test
+    void testNullThrowException() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", null);
+        JexlExpression e = jexl.createExpression("x / y");
+        Assertions.assertThrows(JexlException.class, () -> 
e.evaluate(context));
+    }
+    
+    @Test
+    void testEmptyStringThrowException() {
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", 8);
+        context.set("y", "");
+        JexlExpression e = jexl.createExpression("x / y");
+        Assertions.assertThrows(JexlException.class, () -> 
e.evaluate(context));
+    }
+    
+    @Test
+    void testEqualsFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        context.set("y", "hello");
+        JexlExpression e = jexl.createExpression("sys:equals(x, y)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testNotEqualsFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hellos");
+        context.set("y", "hello");
+        JexlExpression e = jexl.createExpression("sys:equals(x, y)");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+
+    @Test
+    void testContainsFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put(null, new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        context.set("y", "e");
+        JexlExpression e = jexl.createExpression("contains(x, y)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testExistsFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:exists(x)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testExistsFunctionWithNull() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        JexlExpression e = jexl.createExpression("sys:exists(x)");
+        Assertions.assertThrows(JexlException.class, () -> 
e.evaluate(context));
+    }
+    
+    @Test
+    void testExistsFunctionWithEmptyString() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "");
+        JexlExpression e = jexl.createExpression("sys:exists(x)");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+
+    @Test
+    void testExistsFunctionWithEmptyStringAndSpace() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", " ");
+        JexlExpression e = jexl.createExpression("sys:exists(x)");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+
+    @Test
+    void testMatchesFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:matches(x, '.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithNull() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", null);
+        JexlExpression e = jexl.createExpression("sys:matches(x, '.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithEmptyString() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "");
+        JexlExpression e = jexl.createExpression("sys:matches(x, '.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithEmptyStringAndSpace() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", " ");
+        JexlExpression e = jexl.createExpression("sys:matches(x, '.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithRegex() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:matches(x, 'he.*')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithRegexNotMatch() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:matches(x, 'he')");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithRegexAndSpace() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put("sys", new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "hello");
+        JexlExpression e = jexl.createExpression("sys:matches(x, 'he.* ')");
+        Object o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testMatchesFunctionWithRegexAndSpace2() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put(null, new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        context.set("x", "Ubuntu50681269");
+        JexlExpression e = jexl.createExpression("matches(x, 
'^[a-zA-Z0-9]+$')");
+        Object o = e.evaluate(context);
+        Assertions.assertTrue((Boolean) o);
+        context.set("x", "Ubuntu_u50681269");
+        o = e.evaluate(context);
+        Assertions.assertFalse((Boolean) o);
+    }
+    
+    @Test
+    void testNowFunction() {
+        Map<String, Object> functions = Maps.newLinkedHashMap();
+        functions.put(null, new JexlCommonFunction());
+        jexlBuilder.namespaces(functions);
+        JexlEngine jexl = jexlBuilder.create();
+        JexlContext context = new MapContext();
+        JexlExpression e = jexl.createExpression("now() + '-0'");
+        Object o = e.evaluate(context);
+        String result = (String) o;
+        Assertions.assertTrue(result.endsWith("-0"));
+    }
+    
+    @Test
+    void testUnconventionalMapping() {
+        // database_pages=Database pages
+        // name=User Commits Per Sec
+        JexlEngine jexl = jexlBuilder.create();
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("Database pages"));
+        Assertions.assertDoesNotThrow(() -> 
jexl.createExpression("Database_pages"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("User Commits Per Sec"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("System I/O"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("User I/O"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("Library Cache Hit Ratio"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("Buffer Cache Hit Ratio"));
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("Page reads/sec"));
+    }
+    
+    @Test
+    void testRecException() {
+        JexlEngine jexl = jexlBuilder.create();
+        Assertions.assertThrows(JexlException.class, () -> 
jexl.createExpression("new java.util.Date()"));
+    }
+    
+    /**
+     * custom function
+     */
+    public static class DateFunction {
+        public String now(Object... args) {
+            return System.currentTimeMillis() + "-" + args.length;
+        }
+    }
+}
diff --git 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/alert_threshold_expr.md
 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/alert_threshold_expr.md
index 14fbcdb13..f7c8316c7 100644
--- 
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/alert_threshold_expr.md
+++ 
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/alert_threshold_expr.md
@@ -28,7 +28,7 @@ equals(str1,str2)
 
 #### 表达式函数库列表
 
-参考: https://www.yuque.com/boyan-avfmj/aviatorscript/ashevw
+todo 
 
 #### 支持的环境变量    
 > 环境变量即指标值等支持的变量,用于在表达式中,阈值计算判断时会将变量替换成实际值进行计算    
diff --git 
a/manager/src/test/java/org/apache/hertzbeat/manager/ManagerTest.java 
b/manager/src/test/java/org/apache/hertzbeat/manager/ManagerTest.java
index b29345046..22bbb369f 100644
--- a/manager/src/test/java/org/apache/hertzbeat/manager/ManagerTest.java
+++ b/manager/src/test/java/org/apache/hertzbeat/manager/ManagerTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.hertzbeat.manager;
 
+import javax.annotation.Resource;
+import javax.naming.NamingException;
 import org.apache.hertzbeat.alert.AlerterProperties;
 import org.apache.hertzbeat.alert.AlerterWorkerPool;
 import org.apache.hertzbeat.alert.calculate.CalculateAlarm;
@@ -35,7 +37,6 @@ import org.apache.hertzbeat.collector.dispatch.WorkerPool;
 import 
org.apache.hertzbeat.collector.dispatch.entrance.internal.CollectJobService;
 import org.apache.hertzbeat.collector.dispatch.timer.TimerDispatcher;
 import org.apache.hertzbeat.collector.dispatch.unit.impl.DataSizeConvert;
-import org.apache.hertzbeat.common.config.AviatorConfiguration;
 import org.apache.hertzbeat.common.config.CommonConfig;
 import org.apache.hertzbeat.common.config.CommonProperties;
 import org.apache.hertzbeat.common.queue.impl.InMemoryCommonDataQueue;
@@ -50,10 +51,6 @@ import 
org.apache.hertzbeat.warehouse.store.RealTimeRedisDataStorage;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.context.ApplicationContext;
-
-import javax.annotation.Resource;
-import javax.naming.NamingException;
-
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -93,7 +90,6 @@ class ManagerTest extends AbstractSpringIntegrationTest {
         // test common module
         assertNotNull(ctx.getBean(CommonProperties.class));
         assertNotNull(ctx.getBean(CommonConfig.class));
-        assertNotNull(ctx.getBean(AviatorConfiguration.class));
         assertNotNull(ctx.getBean(InMemoryCommonDataQueue.class));
         // condition on common.sms.tencent.app-id
         assertThrows(NoSuchBeanDefinitionException.class, () -> 
ctx.getBean(TencentSmsClient.class));
diff --git a/material/licenses/backend/LICENSE 
b/material/licenses/backend/LICENSE
index 0116e2fc6..963e21187 100644
--- a/material/licenses/backend/LICENSE
+++ b/material/licenses/backend/LICENSE
@@ -409,6 +409,7 @@ The text of each license is the standard Apache 2.0 license.
     
https://mvnrepository.com/artifact/com.github.GreptimeTeam/greptime-proto/0.4.0
     https://mvnrepository.com/artifact/org.webjars/swagger-ui/5.10.3
     
https://mvnrepository.com/artifact/com.google.flatbuffers/flatbuffers-java/1.12.0
+    https://mvnrepository.com/artifact/org.apache.commons/commons-jexl3/3.2.1
 
 
 ========================================================================
@@ -527,13 +528,3 @@ The following components are provided under the 
https://spdx.org/licenses/MIT-0.
 The text of each license is also included in licenses/LICENSE-[project].txt.
 
     
https://mvnrepository.com/artifact/org.reactivestreams/reactive-streams/1.0.4 
https://spdx.org/licenses/MIT-0.html
-
-
-========================================================================
-LGPL-2.1 licenses
-========================================================================
-The following components are provided under the LGPL-2.1 License. See project 
link for details.
-The text of each license is also included in licenses/LICENSE-[project].txt.
-
-    https://mvnrepository.com/artifact/com.googlecode.aviator/aviator/5.4.1 
http://www.gnu.org/licenses/lgpl.html
-
diff --git a/material/licenses/backend/LICENSE-aviator.txt 
b/material/licenses/backend/LICENSE-aviator.txt
deleted file mode 100644
index 02bbb60bc..000000000
--- a/material/licenses/backend/LICENSE-aviator.txt
+++ /dev/null
@@ -1,165 +0,0 @@
-                   GNU LESSER GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
-  This version of the GNU Lesser General Public License incorporates
-the terms and conditions of version 3 of the GNU General Public
-License, supplemented by the additional permissions listed below.
-
-  0. Additional Definitions.
-
-  As used herein, "this License" refers to version 3 of the GNU Lesser
-General Public License, and the "GNU GPL" refers to version 3 of the GNU
-General Public License.
-
-  "The Library" refers to a covered work governed by this License,
-other than an Application or a Combined Work as defined below.
-
-  An "Application" is any work that makes use of an interface provided
-by the Library, but which is not otherwise based on the Library.
-Defining a subclass of a class defined by the Library is deemed a mode
-of using an interface provided by the Library.
-
-  A "Combined Work" is a work produced by combining or linking an
-Application with the Library.  The particular version of the Library
-with which the Combined Work was made is also called the "Linked
-Version".
-
-  The "Minimal Corresponding Source" for a Combined Work means the
-Corresponding Source for the Combined Work, excluding any source code
-for portions of the Combined Work that, considered in isolation, are
-based on the Application, and not on the Linked Version.
-
-  The "Corresponding Application Code" for a Combined Work means the
-object code and/or source code for the Application, including any data
-and utility programs needed for reproducing the Combined Work from the
-Application, but excluding the System Libraries of the Combined Work.
-
-  1. Exception to Section 3 of the GNU GPL.
-
-  You may convey a covered work under sections 3 and 4 of this License
-without being bound by section 3 of the GNU GPL.
-
-  2. Conveying Modified Versions.
-
-  If you modify a copy of the Library, and, in your modifications, a
-facility refers to a function or data to be supplied by an Application
-that uses the facility (other than as an argument passed when the
-facility is invoked), then you may convey a copy of the modified
-version:
-
-   a) under this License, provided that you make a good faith effort to
-   ensure that, in the event an Application does not supply the
-   function or data, the facility still operates, and performs
-   whatever part of its purpose remains meaningful, or
-
-   b) under the GNU GPL, with none of the additional permissions of
-   this License applicable to that copy.
-
-  3. Object Code Incorporating Material from Library Header Files.
-
-  The object code form of an Application may incorporate material from
-a header file that is part of the Library.  You may convey such object
-code under terms of your choice, provided that, if the incorporated
-material is not limited to numerical parameters, data structure
-layouts and accessors, or small macros, inline functions and templates
-(ten or fewer lines in length), you do both of the following:
-
-   a) Give prominent notice with each copy of the object code that the
-   Library is used in it and that the Library and its use are
-   covered by this License.
-
-   b) Accompany the object code with a copy of the GNU GPL and this license
-   document.
-
-  4. Combined Works.
-
-  You may convey a Combined Work under terms of your choice that,
-taken together, effectively do not restrict modification of the
-portions of the Library contained in the Combined Work and reverse
-engineering for debugging such modifications, if you also do each of
-the following:
-
-   a) Give prominent notice with each copy of the Combined Work that
-   the Library is used in it and that the Library and its use are
-   covered by this License.
-
-   b) Accompany the Combined Work with a copy of the GNU GPL and this license
-   document.
-
-   c) For a Combined Work that displays copyright notices during
-   execution, include the copyright notice for the Library among
-   these notices, as well as a reference directing the user to the
-   copies of the GNU GPL and this license document.
-
-   d) Do one of the following:
-
-       0) Convey the Minimal Corresponding Source under the terms of this
-       License, and the Corresponding Application Code in a form
-       suitable for, and under terms that permit, the user to
-       recombine or relink the Application with a modified version of
-       the Linked Version to produce a modified Combined Work, in the
-       manner specified by section 6 of the GNU GPL for conveying
-       Corresponding Source.
-
-       1) Use a suitable shared library mechanism for linking with the
-       Library.  A suitable mechanism is one that (a) uses at run time
-       a copy of the Library already present on the user's computer
-       system, and (b) will operate properly with a modified version
-       of the Library that is interface-compatible with the Linked
-       Version.
-
-   e) Provide Installation Information, but only if you would otherwise
-   be required to provide such information under section 6 of the
-   GNU GPL, and only to the extent that such information is
-   necessary to install and execute a modified version of the
-   Combined Work produced by recombining or relinking the
-   Application with a modified version of the Linked Version. (If
-   you use option 4d0, the Installation Information must accompany
-   the Minimal Corresponding Source and Corresponding Application
-   Code. If you use option 4d1, you must provide the Installation
-   Information in the manner specified by section 6 of the GNU GPL
-   for conveying Corresponding Source.)
-
-  5. Combined Libraries.
-
-  You may place library facilities that are a work based on the
-Library side by side in a single library together with other library
-facilities that are not Applications and are not covered by this
-License, and convey such a combined library under terms of your
-choice, if you do both of the following:
-
-   a) Accompany the combined library with a copy of the same work based
-   on the Library, uncombined with any other library facilities,
-   conveyed under the terms of this License.
-
-   b) Give prominent notice with the combined library that part of it
-   is a work based on the Library, and explaining where to find the
-   accompanying uncombined form of the same work.
-
-  6. Revised Versions of the GNU Lesser General Public License.
-
-  The Free Software Foundation may publish revised and/or new versions
-of the GNU Lesser General Public License from time to time. Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-
-  Each version is given a distinguishing version number. If the
-Library as you received it specifies that a certain numbered version
-of the GNU Lesser General Public License "or any later version"
-applies to it, you have the option of following the terms and
-conditions either of that published version or of any later version
-published by the Free Software Foundation. If the Library as you
-received it does not specify a version number of the GNU Lesser
-General Public License, you may choose any version of the GNU Lesser
-General Public License ever published by the Free Software Foundation.
-
-  If the Library as you received it specifies that a proxy can decide
-whether future versions of the GNU Lesser General Public License shall
-apply, that proxy's public statement of acceptance of any version is
-permanent authorization for you to choose that version for the
-Library.
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index a95019724..cfb442ab2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -107,7 +107,6 @@
 
         <nekohtml.version>1.9.22</nekohtml.version>
         <json-path.version>2.9.0</json-path.version>
-        <aviator.version>5.4.1</aviator.version>
         <gson.version>2.10.1</gson.version>
         <guava.version>32.1.2-jre</guava.version>
         <protobuf.version>3.19.6</protobuf.version>
@@ -134,6 +133,7 @@
         <taos-jdbcdriver.version>3.0.0</taos-jdbcdriver.version>
         <iotdb-session.version>0.13.3</iotdb-session.version>
         <commons-collections4.version>4.4</commons-collections4.version>
+        <commons-jexl3>3.2.1</commons-jexl3>
         <commons-net>3.10.0</commons-net>
     </properties>
 
@@ -229,6 +229,11 @@
                 <artifactId>httpclient</artifactId>
                 <version>${httpclient.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-jexl3</artifactId>
+                <version>${commons-jexl3}</version>
+            </dependency>
             <!-- mysql -->
             <dependency>
                 <groupId>mysql</groupId>
@@ -318,12 +323,7 @@
                 <artifactId>json-path</artifactId>
                 <version>${json-path.version}</version>
             </dependency>
-            <!-- 表达式计算 -->
-            <dependency>
-                <groupId>com.googlecode.aviator</groupId>
-                <artifactId>aviator</artifactId>
-                <version>${aviator.version}</version>
-            </dependency>
+            <!-- protobuf -->
             <dependency>
                 <groupId>com.google.protobuf</groupId>
                 <artifactId>protobuf-java-util</artifactId>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to