:: 上下文调用更强大的机制,允许执行器完全控制代码块的执行时机、方式和环境。
Domain 的核心特性是闭包语义:执行器接收的是未求值的 AST,可以决定是否执行、何时执行、执行多少次。
适用场景
- 异步执行:
async { fetch("http://api.example.com") } - 事务管理:
transaction { updateDatabase(); commit() } - 重试逻辑:
retry { unstableOperation() } - 结构化并发:
scope { async { task1() }; async { task2() } } - 条件执行:
lazy { expensiveComputation() }
与其他机制的区别
Domain 的字节码生成会抛
UnsupportedOperationException,因此含 domain 的脚本不要走
编译执行引擎。组成与执行流程
执行大致流程:
- Parser 读到
IDENTIFIER,DomainSyntaxMacro发现已注册同名 domain。 - 先消费 domain 名称 token,再解析后续的块或表达式作为域体。
- 域体 AST 与
DomainExecutor一起被封装进DomainExpression。 - Interpreter 执行到该节点时,将域体包装为
Supplier<Object>并调用 executor。
注册与隔离
使用全局主注册表(最常见)
在应用启动时注册即可(建议注册阶段单线程):为沙箱/多租户使用独立注册表
如果你需要”每份脚本一套 domain 集合”,可以创建独立实例并放到CompilationContext:
如果你也自定义了
SyntaxMacroRegistry,记得把 DomainSyntaxMacro 放进去;
否则即使 registry 有 domain,解析器也不会命中。最小示例:实现 retry
这个 domain 失败时最多重试 3 次:
高级用法:通过 target 实现结构化并发
Domain 可以通过Environment#setTarget(Object) 设置上下文对象,使内部代码能够访问域的上下文。
这是实现结构化并发、事务等协作模式的基础。
示例:Scope + Async
Target 类型检查约定
推荐使用instanceof 进行类型检查:
常见模式
1. 异步执行
2. 结果转换
3. 条件执行(惰性求值)
4. 环境修改
注意事项
- 命名规则:domain 名称是标识符(
IDENTIFIER),允许包含-(例如retry-3-times)。 - 命名冲突:domain 的匹配发生在”标识符兜底”之前, 如果你注册了与函数/变量同名的 domain,会改变解析结果。
- 闭包捕获:域体是闭包,可以访问外部作用域的变量。
- 异常处理:
- 执行器内抛出的异常会传播到调用方。
- 建议抛出
FluxonRuntimeError子类以获得 SourceTrace。
- 线程安全:
DomainExecutor可能在多线程环境下被并发调用,应保证无状态或正确处理并发访问。Environment不是线程安全的,异步执行时需要创建新的环境或使用同步机制。
相关链接
- Command 接口 - 用于自定义 DSL 语法的扩展机制
- 运行时注册 API
- 扩展函数 API
- 命令行与 REPL
- 编译执行引擎