diff --git a/src/main/java/com/ql/util/express/ExpressRunner.java b/src/main/java/com/ql/util/express/ExpressRunner.java index 25169716b..4c33d6c4e 100644 --- a/src/main/java/com/ql/util/express/ExpressRunner.java +++ b/src/main/java/com/ql/util/express/ExpressRunner.java @@ -76,6 +76,11 @@ public class ExpressRunner { */ ExpressPackage rootExpressPackage = new ExpressPackage(null); + /** + * 线程冲入次数 + */ + private final ThreadLocal threadReentrantCount = ThreadLocal.withInitial(() -> 0); + public AppendingClassMethodManager getAppendingClassMethodManager() { return appendingClassMethodManager; } @@ -613,8 +618,24 @@ public Object execute(String expressString, IExpressContext conte } else { parseResult = this.parseInstructionSet(expressString); } - return InstructionSetRunner.executeOuter(this,parseResult,this.loader,context, errorList, - isTrace,false,aLog,false); + return executeReentrant(parseResult, context, errorList, isTrace, aLog); + } + + private Object executeReentrant(InstructionSet sets, IExpressContext aContext, + List errorList, boolean isTrace, Log aLog) throws Exception { + try { + int reentrantCount = threadReentrantCount.get() + 1; + threadReentrantCount.set(reentrantCount); + + return reentrantCount > 1? + // 线程重入 + InstructionSetRunner.execute(this, sets, this.loader, aContext, errorList, + isTrace, false, true, aLog, false): + InstructionSetRunner.executeOuter(this, sets, this.loader, aContext, errorList, + isTrace,false,aLog,false); + } finally { + threadReentrantCount.set(threadReentrantCount.get() - 1); + } } public RuleResult executeRule(String expressString, IExpressContext context, boolean isCache, boolean isTrace) diff --git a/src/test/java/com/ql/util/express/bugfix/ExecuteReentrantTest.java b/src/test/java/com/ql/util/express/bugfix/ExecuteReentrantTest.java new file mode 100644 index 000000000..e31e29d02 --- /dev/null +++ b/src/test/java/com/ql/util/express/bugfix/ExecuteReentrantTest.java @@ -0,0 +1,40 @@ +package com.ql.util.express.bugfix; + +import com.ql.util.express.ArraySwap; +import com.ql.util.express.DefaultContext; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.OperateData; +import com.ql.util.express.instruction.op.OperatorBase; +import org.junit.Assert; +import org.junit.Test; + +/** + * 线程可重入执行测试 + */ +public class ExecuteReentrantTest { + + @Test + public void executeReentrantTest() throws Exception { + String express = "eval('eval(\\'1+1\\')')"; + ExpressRunner runner = new ExpressRunner(false, true); + runner.addFunction("eval", new OperatorBase() { + @Override + public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception { + Object res = runner.execute(list.get(0).toString(), parent, null, + false, true); + return new OperateData(res, res.getClass()); + } + }); + + Object res = runner.execute(express, new DefaultContext<>(), null, + false, true); + Assert.assertEquals(2, res); + + Object res1 = runner.execute("m = 'aaa';" + + "eval('m')", new DefaultContext<>(), null, + false, true); + Assert.assertEquals("aaa", res1); + } + +}