Skip to main content

自定义 Kit 开发

内置 kit(见内置 Kit)之外,集成方可以把自有能力开发为 kit 注入脚本:一个标注注解的 Java 类 + 一次注册。SDK 内置的 cn.geelato.script.kit.demo.DemoService 是参考模板。

注解模型​

kit 的全部元数据来自两个注解(定义于 cn.geelato.core.graal):

@GraalService(name = "demo", built = "true", descrption = "演示 kit(模板):hello/add")
public class DemoService {

private final KitContext ctx;

public DemoService(KitContext ctx) {
this.ctx = ctx;
}

@GraalFunction(example = "$gl.demo.hello('world')", description = "回显问好并携带本次执行 execId")
public Map<String, Object> hello(String name) {
return Map.of(
"message", "hello " + (name == null || name.isBlank() ? "world" : name),
"execId", String.valueOf(ctx.getExecId()));
}

@GraalFunction(example = "$gl.demo.add(1, 2)", description = "两数相加")
public long add(long a, long b) {
return a + b;
}
}
注解属性说明
@GraalService.name脚本侧命名空间,也是注册与档案白名单匹配的 key,全局唯一(冲突启动即报错)
@GraalService.built"true" 挂到 $gl.{name};"false"(缺省)挂顶层变量 ${name}
@GraalService.descrption描述文本,进 $gl.help() 与 catalog 清单
@GraalFunction.example调用示例,进 help 详情与 catalog,供编辑器补全展示
@GraalFunction.description方法说明

只有标注 @GraalFunction 的 public 方法会暴露给脚本,其余方法不可见。

方法签名约束​

参数与返回类型必须在 interop 兼容白名单内,否则启动即 fail-fast(IllegalStateException,指明类#方法与违规类型):

  • 参数允许:String、数值(Number 家族与原始类型)、Boolean、Map、List、Date、Object、polyglot Value;
  • 返回允许:同上外加 void;
  • 泛型集合按原始类型(Map/List)判定;Set 等其他类型不支持。

单例与 scoped​

形态判定方式生命周期适用
单例无参构造器,或以实例注册全引擎复用一个实例无状态 kit
scoped声明 (KitContext) 构造器(唯一 public 构造器参数恰为 KitContext),或经 registerScoped 工厂通道注册每次执行实例化,互不串扰需要执行级上下文的 kit

scoped kit 经构造器拿到的 KitContext 是单次执行的上下文:execId、身份快照(identity)、注入变量(bindings,$gl.ctx/$gl.parameter 的数据源)、执行级属性袋(attributes)、行数计数器(addRows)、kit 调用留痕(record)以及宿主装配的 SPI(数据源、ORM 供给等)。

带外部依赖(Spring Bean 等)不适合构造器直接创建时,走工厂通道:

builder.registerScoped("demo", DemoService.class, ctx -> new DemoService(depService, ctx));

注册方式(三选一)​

1. 配置扫描:把 kit 所在包加入扫描清单,无需写注册代码:

geelato.script.engine.scan-packages=cn.geelato.example.rulekit

2. 编程注册:非 Spring 环境或单测中直接在 Builder 上注册(Spring Bean 优先传实例,避免重复实例化):

ScriptEngine engine = new ScriptEngineBuilder()
.registerKit(new DemoKit()) // 实例(恒单例)
.registerKit(OtherKit.class) // 类(按构造器形状判定 scoped)
.build();

3. Spring 定制器:定义 ScriptEngineCustomizer Bean,自动装配时按序应用:

@Bean
public ScriptEngineCustomizer demoKitCustomizer() {
return builder -> builder.registerKit(new DemoKit());
}

命名空间冲突(两个 kit 同 name)在注册时即抛错,不会静默覆盖。

与内置 kit 同名​

build() 默认注册六个内置 kit,但仅当注册表中尚无同名 kit 时——消费方显式注册(registerKit/registerScoped/扫描)同名者优先,内置版本被跳过。可用它整体替换某个内置 kit 的实现(如换成走专属数据源的 $gl.sql)。

版本化固化​

把自定义 kit 固化到某个引擎版本快照,供脚本按 engineVersion 路由(引擎版本语义见脚本使用手册)。以基线版本为底声明差异,构建期派生注册:

ScriptEngine engine = new ScriptEngineBuilder()
.registerKit(new RuleKitV2()) // 先注册(进缺省版本)
.deriveRevision("v2", "v1", deriver -> deriver
.scoped("rule", RuleKitV2.class) // v2 用新实现覆盖 rule 命名空间
.remove("legacy") // 移除不再暴露的 kit
.esVersion("2023")) // 语言级别差异(可选)
.build();

RevisionDeriver 差异声明项:singleton(ns, kit) 覆盖/新增无状态 kit、scoped(ns, clazz[, factory]) 覆盖/新增 scoped kit、remove(ns) 移除、esVersion(...) 语言级别、status(...) 注册时初始状态(缺省 CURRENT)。派生出的 kit 同样经 interop 白名单 fail-fast 校验;ns 须与 @GraalService.name 一致。

验证​

注册完成后三种自检方式:

  • 脚本内 $gl.help() / $gl.help('demo') 打印可见 kit 与方法;
  • GET /api/script/catalog 拉取结构化清单(开启 geelato.script.rest.enabled);
  • KitDtsGenerator.generate(...) 生成 .d.ts 声明文件,在 IDE 中获得补全提示。

第三方 Java 库无需逐个写 kit 类即可整库引入,见第三方库引入。