From 086468d8ec6cea6cc2c86aa4bc4eeff62e460cfa Mon Sep 17 00:00:00 2001 From: chenzhangyue Date: Wed, 17 Dec 2025 11:30:52 +0800 Subject: [PATCH] =?UTF-8?q?enhancement:=20QLExpress4=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89ClassSupplier=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=8C=96=E5=9C=BA=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - QLExpressScriptExecutor新增reinit方法,支持运行时重新初始化引擎 - 新增setClassSupplier/getClassSupplier静态方法管理ClassSupplier - ScriptExecutorFactory新增getLoadedScriptExecutor和reinitScriptExecutor方法 - 适用于插件化场景,在插件类加载器准备好后可动态设置ClassSupplier 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../script/ScriptExecutorFactory.java | 35 +++++++++++ .../qlexpress/QLExpressScriptExecutor.java | 63 ++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutorFactory.java b/liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutorFactory.java index 1b2b56160..7221206fa 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutorFactory.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutorFactory.java @@ -73,4 +73,39 @@ public void cleanScriptCache() { this.scriptExecutorMap.forEach((key, value) -> value.cleanCache()); } + /** + * 根据脚本类型获取已加载的脚本执行器(不会触发新加载) + * + * @param scriptType 脚本类型枚举 + * @return 脚本执行器,如果未加载则返回null + */ + public ScriptExecutor getLoadedScriptExecutor(ScriptTypeEnum scriptType) { + if (ObjectUtil.isNull(scriptType)) { + return null; + } + return scriptExecutorMap.get(scriptType.getDisplayName()); + } + + /** + * 重新初始化指定类型的脚本执行器 + * 此方法适用于需要在运行时更换脚本引擎配置的场景(如插件化场景下更换ClassLoader) + * + * @param language 脚本语言类型 + * @return 重新初始化后的脚本执行器 + */ + public ScriptExecutor reinitScriptExecutor(String language) { + if (StrUtil.isBlank(language)) { + language = NONE_LANGUAGE; + } + + ScriptExecutor executor = scriptExecutorMap.get(language); + if (ObjectUtil.isNotNull(executor)) { + // 重新初始化 + executor.init(); + return executor; + } + // 如果还未加载,则走正常加载流程 + return getScriptExecutor(language); + } + } diff --git a/liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java b/liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java index c0150d87b..f61d70f38 100644 --- a/liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java +++ b/liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java @@ -5,6 +5,7 @@ import com.alibaba.qlexpress4.QLResult; import com.alibaba.qlexpress4.InitOptions; import com.alibaba.qlexpress4.QLOptions; +import com.alibaba.qlexpress4.ClassSupplier; import com.alibaba.qlexpress4.security.QLSecurityStrategy; import com.yomahub.liteflow.enums.ScriptTypeEnum; import com.yomahub.liteflow.script.ScriptExecuteWrap; @@ -32,9 +33,69 @@ public class QLExpressScriptExecutor extends ScriptExecutor { private final Map compiledScriptMap = new CopyOnWriteHashMap<>(); + /** + * 预设的ClassSupplier,用于延迟初始化场景(如插件化) + * 在Spring初始化完成后,插件加载器可以通过 setClassSupplier 方法设置自定义的ClassSupplier, + * 然后调用 reinit() 方法重新初始化QLExpress引擎 + */ + private static volatile ClassSupplier presetClassSupplier; + + /** + * 设置预设的ClassSupplier,用于插件化场景 + * 应在插件类加载器准备好之后、调用reinit()之前设置 + * + * @param classSupplier 自定义的ClassSupplier实现 + */ + public static void setClassSupplier(ClassSupplier classSupplier) { + presetClassSupplier = classSupplier; + } + + /** + * 获取当前预设的ClassSupplier + * + * @return 当前预设的ClassSupplier,如果未设置则返回null + */ + public static ClassSupplier getClassSupplier() { + return presetClassSupplier; + } + @Override public ScriptExecutor init() { - expressRunner = new Express4Runner(InitOptions.builder().securityStrategy(QLSecurityStrategy.open()).build()); + return doInit(presetClassSupplier); + } + + /** + * 使用指定的ClassSupplier重新初始化QLExpress引擎 + * 此方法适用于插件化场景,在插件类加载器准备好之后调用 + * + * @param classSupplier 自定义的ClassSupplier实现 + * @return this + */ + public ScriptExecutor reinit(ClassSupplier classSupplier) { + // 清理已编译的脚本缓存 + compiledScriptMap.clear(); + if (expressRunner != null) { + expressRunner.clearCompileCache(); + } + // 更新预设的ClassSupplier + presetClassSupplier = classSupplier; + return doInit(classSupplier); + } + + /** + * 内部初始化方法 + */ + private ScriptExecutor doInit(ClassSupplier classSupplier) { + InitOptions.Builder optionsBuilder = InitOptions.builder() + .securityStrategy(QLSecurityStrategy.open()); + + // 使用传入的ClassSupplier + if (classSupplier != null) { + optionsBuilder.classSupplier(classSupplier); + log.info("QLExpress4 using custom ClassSupplier: {}", classSupplier.getClass().getName()); + } + + expressRunner = new Express4Runner(optionsBuilder.build()); //如果有生命周期则执行相应生命周期实现 super.lifeCycle(expressRunner); return this;