You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JVM宿主代码中访问JSR223 ScriptEngine定义的Kotlin类

问题原因解释

你遇到的ClassNotFoundException本质是类加载器隔离导致的:Kotlin的ScriptEngine执行脚本时,会使用独立的自定义类加载器编译、加载脚本中定义的类,这个类加载器和宿主应用的默认类加载器是父子隔离关系,宿主的Class.forName默认使用当前线程的上下文类加载器(也就是宿主自身的类加载器),自然找不到脚本引擎加载的类。

是否只能通过eval获取类引用?

不是,有两种常用的实现方式,你目前用的eval方案是兼容性最好的首选方案:

  • 方案1:直接通过eval返回类引用(推荐)
    就是你现在正在使用的写法,不需要关心类加载器、脚本类全限定名规则的差异,不同版本的Kotlin脚本引擎都兼容,代码实现最简洁:

    val fooKClass = scriptEngine.eval("MyFoo::class") as KClass<Foo>
    val foo = fooKClass.createInstance()
    foo.bar()
    
  • 方案2:通过脚本引擎的类加载器加载类
    JSR223规范中脚本引擎的上下文会暴露自身使用的类加载器,你可以拿到这个类加载器后传给Class.forName,就能加载到脚本中定义的类:

    // 先获取脚本引擎的类加载器
    val scriptClassLoader = scriptEngine.getContext().classLoader
    // 传入类加载器加载类
    val fooKClass = Class.forName("MyFoo", true, scriptClassLoader).kotlin as KClass<Foo>
    val foo = fooKClass.createInstance()
    foo.bar()
    

    注意:部分版本的Kotlin脚本引擎会对脚本中的顶级类自动加前缀或后缀,如果你用上面的代码还是找不到类,可以先执行scriptEngine.eval("MyFoo::class.qualifiedName")打印出类的实际全限定名,再替换到Class.forName的第一个参数即可。

关于把脚本类注入宿主类加载器

理论上可以通过修改Kotlin脚本引擎的编译配置,指定脚本生成的类直接注入到宿主的类加载器,但这个属于版本相关的高级特性,兼容性很差,一般业务场景完全没有必要用。


内容的提问来源于stack exchange,提问作者Dan Lugg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 11:15:06