1. Avaitor
1.1 what is Avatar?
Aviator is a high-performance and lightweight expression evaluation engine implemented in Java language, which is mainly used for dynamic evaluation of expressions.
1.2 why do you need avitor?
The design goal of Aviator is lightweight and high performance. Compared with the bulkiness of Groovy and JRuby, Aviator is very small. In addition, the dependent package is 450K, not 70K. However, Aviator has limited syntax. It is not a complete language, but a small collection of languages.
1.3 characteristics of Avatar
The implementation idea of aviator is different from other lightweight evaluators. Other evaluators run by interpretation, while Aviator directly compiles expressions into Java bytecode and sends them to the JVM for execution.
Aviator is positioned between a heavyweight scripting language like Groovy and a lightweight expression engine like ikeexpression.
1.4 functions of avitor
• support most arithmetic operators, including arithmetic operators, relational operators, logical operators, regular matching operators and ternary expressions, as well as the priority of operators and the mandatory priority of parentheses.
• support function calls and custom functions
• support regular expression matching
• automatic type conversion. When the operation is performed, the operand type will be automatically determined and converted accordingly. If it cannot be converted, an exception will be thrown
• support incoming variables and nested variable access similar to a.b.c.
• excellent performance
1.5 usage scenarios
• rule judgment and rule engine
• formula calculation
• dynamic script control
Wait
1.6 how to use avitor?
Create an empty Maven project and import the following dependencies
<dependency> <groupId>com.googlecode.aviator</groupId> <artifactId>aviator</artifactId> <version>5.1.4</version> </dependency>
A simple example:
//Aviator is used centrally through COM googlecode. aviator. Aviatorevaluator is an entry class to handle public void test1() { Long sum = (Long)AviatorEvaluator.execute("1 + 2 + 3"); System.out.println(sum); } //The result is: 6
Note: the value type of Aviator only supports Long and Double. Any integer will be converted to Long and any floating-point number will be converted to Double, including the variable value passed in by the user.
Other examples:
public class AviatorSimpleTest { /** * Arithmetic expression */ @Test public void test1() { Long sum = (Long)AviatorEvaluator.execute("1 + 2 + 3"); System.out.println(sum); } /** * Logical expression */ @Test public void test2() { Boolean result = (Boolean)AviatorEvaluator.execute("3 > 1 && 2 != 4 || true"); System.out.println(result); } /** * Pass a value into the expression */ @Test public void test3() { Map<String, Object> env = new HashMap<>(); env.put("name", "ruilin.shao"); String str = "'hello ' + name"; String result = (String) AviatorEvaluator.execute(str, env); System.out.println(result); //Writing method 2 String result2 = (String)AviatorEvaluator.exec(str, "Convenient bee"); System.out.println(result2); } /** * Ternary expression */ @Test public void test4() { String result = (String)AviatorEvaluator.execute("3 > 0 ? yes : no"); System.out.println(result); } /** * function call */ @Test public void test5() { System.out.println("string.length('hello') = " + AviatorEvaluator.execute("string.length('hello')"));//Find the length of a string. String. Is not allowed length(); System.out.println("string.contains('hello', 'h') = " + AviatorEvaluator.execute("string.contains('hello', 'h')"));//Determine whether a string is included in the string System.out.println("math.pow(-3, 2) = " + AviatorEvaluator.execute("math.pow(-3, 2)")); System.out.println("math.sqrt(9.0) = " + AviatorEvaluator.execute("math.sqrt(9.0)")); } }
1.7 Aviator custom functions
Aviator not only defines some functions internally, but also supports user-defined functions. It only needs to implement com googlecode. aviator. runtime. type. Aviatorfunction interface and register with AviatorEvaluator
To create a custom function:
public class UserDefinedFunction extends AbstractFunction { //Name of custom feature @Override public String getName() { return "multi"; } @Override public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) { Number left = FunctionUtils.getNumberValue(arg1, env); Number right = FunctionUtils.getNumberValue(arg2, env); return new AviatorDouble(left.doubleValue() * right.doubleValue()); } }
Using custom functions
@Test public void test6() { //Register function AviatorEvaluator.addFunction(new UserDefinedFunction()); System.out.println("multi(2, 3) = " + AviatorEvaluator.execute("multi(2, 3)")); //Remove function AviatorEvaluator.removeFunction("multi"); //If the following statement is executed after removal, an error will be reported //System.out.println("multi(2, 3) = " + AviatorEvaluator.execute("multi(2, 3)")); }
1.8 compiling expressions
In fact, every time you execute aviator When execute (), the operations behind it have been compiled and executed.
Then we can compile the expression first, return a compiled result, and then pass in different env s to reuse the compiled result, which can improve the performance.
/** * Performance testing of compiled and uncompiled expressions */ @Test public void test8() { String expression = "a * (b + c)"; Map<String, Object> env = new HashMap<>(); env.put("a", 3.32); env.put("b", 234); env.put("c", 324.2); //Compile expression Expression compliedExp = AviatorEvaluator.compile(expression); long startTime = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { Double result = (Double) compliedExp.execute(env); } long endTime = System.currentTimeMillis(); System.out.println("The time taken for precompiling is:" + (endTime - startTime)); long startTime2 = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { Double result = (Double) AviatorEvaluator.execute(expression, env); } long endTime2 = System.currentTimeMillis(); System.out.println("The time consuming without compilation is:" + (endTime2 - startTime2)); }
The Expression can be compiled into an intermediate object of Expression through the compile method. When the Expression is to be executed, the Map object is passed in and the execute method of Expression can be called directly.
The compiled results can be cached by themselves or given to Aviator to help you cache. AviatorEvaluator has another global cache pool. If you want to help you cache through aviator, you can use the following methods:
public static Expression complie(String expression, boolean cached);
give an example:
/** * Precompiled cache example */ @Test public void test9() { String expression1 = "a + b + c"; Expression compiledExp1 = AviatorEvaluator.compile(expression1, true); Expression compiledExp2 = AviatorEvaluator.compile(expression1, true); Expression compiledExp3 = AviatorEvaluator.compile(expression1, false); System.out.println("compiledExp1 == compiledExp2 : " + (compiledExp1 == compiledExp2)); System.out.println("compiledExp1 == compiledExp3 : " + (compiledExp1 == compiledExp3)); } //compiledExp1 == compiledExp2 : true //compiledExp1 == compiledExp3 : false
2. Rule engine
2.1 why do you need a rule engine?
Without the rule engine, some business codes with complex logic can only continuously add if - else to meet complex business scenarios. When there are too many if - else, it will make the code extremely difficult to read. Although if - else can be optimized through the policy mode, it still can not solve the problem of slow development and need to go online.
In the risk control system, the logic of risk control is constantly changing. If the code is dead and the logic changes, we need to change the code and go online again. In the case of frequent logic changes, this approach is obviously unacceptable, so we need a rule engine to change the current situation, Change these business rules in an efficient and reliable way.
2.2 benefits of rule engine
• reduce development costs
• business personnel configure business rules independently, and developers do not need to understand. In the past, business personnel need to tell developers that developers need to understand before they can develop, and a large number of tests are needed to determine whether they are correct. Moreover, the development results are easy to deviate from the proposed business, which leads to an increase in development costs
• increase the transparency of the business, which can be seen by other business personnel after the business personnel are configured,
• improve the efficiency of rule changes and the speed of online
2.3 rule engine based on aviator
Through the rule engine, we only need to convert the rules configured by business personnel into a rule string, and then save the rule string into the database. When using the rule, we can directly calculate the results by passing only the parameters required by the rule. Our developers do not need to write any code for these rules.
public class AviatorExampleTwo { //Rules can be saved in the database, such as mysql or redis Map<Integer, String> ruleMap = new HashMap<>(); public AviatorExampleTwo() { //Calculation formula of seconds ruleMap.put(1, "hour * 3600 + minute * 60 + second"); //Calculation formula of cube volume ruleMap.put(2, "height * width * length"); //Judge whether a person is a senior customer ruleMap.put(3, "age >= 18 && sumConsume > 2000 && vip"); //Modification required by senior customers ruleMap.put(4, "age > 10 && sumConsume >= 8000 && vip && avgYearConsume >= 1000"); //Judge whether a person's age is greater than or equal to 18 years old ruleMap.put(5, "age >= 18 ? 'yes' : 'no'"); } public static void main(String[] args) { AviatorExampleTwo aviatorExample = new AviatorExampleTwo(); //Select a rule and pass in the parameters required by the rule System.out.println("Formula 1:" + aviatorExample.getResult(1, 1, 1, 1)); System.out.println("Formula 2:" + aviatorExample.getResult(2, 3, 3, 3)); System.out.println("Equation 3:" + aviatorExample.getResult(3, 20, 3000, false)); System.out.println("Equation 4:" + aviatorExample.getResult(4, 23, 8000, true, 2000)); System.out.println("Equation 5:" + aviatorExample.getResult(5, 12)); } public Object getResult(int ruleId, Object... args) { String rule = ruleMap.get(ruleId); return AviatorEvaluator.exec(rule, args); } } //Formula 1:3661 //Equation 2:27 //Formula 3: false //Formula 4: true //Formula 5: no