Scala 脚本引擎创建另一个单例实例
Scala Script Engine creating another instance of a singleton
所以,我正在使用 JSR 223
为 Scala 创建一个脚本系统,但我遇到了这个问题,我找不到任何原因。
有一个类似单例的 class,它具有添加事件侦听器(来自脚本)和调度事件(来自核心)的方法。一切正常,但由于某种原因,当我开始发送事件时,添加的侦听器消失了。
重现问题后发现脚本引擎又创建了一个单例实例:
这是我的 Singleton
class:
package test;
import java.util.Arrays;
public final class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
Arrays.stream(Thread.currentThread().getStackTrace()).forEach(System.out::println);
System.out.println();
}
public static Singleton instance() {
return instance;
}
}
这是我的 Main
class:
package test;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public final class Main {
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("scala");
// this is a trick I found to access the classpath,
// might be the problem
@SuppressWarnings("rawtypes")
scala.collection.immutable.List nil = scala.collection.immutable.Nil$.MODULE$;
@SuppressWarnings("unchecked")
scala.collection.immutable.$colon$colon<String> vals = scala.collection.immutable.$colon$colon$.MODULE$.apply("true", nil);
((scala.tools.nsc.interpreter.IMain) engine).settings().usejavacp().tryToSet(vals);
engine.eval("test.Singleton.instance");
Singleton.instance();
}
}
这是输出:
java.lang.Thread.getStackTrace(Unknown Source)
test.Singleton.<init>(Singleton.java:10)
test.Singleton.<clinit>(Singleton.java:7)
$line3.$read$$iw$$iw$.<init>(<console>:8)
$line3.$read$$iw$$iw$.<clinit>(<console>)
$line3.$eval$.$result$lzycompute(<console>:5)
$line3.$eval$.$result(<console>:5)
$line3.$eval.$result(<console>)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:773)
scala.tools.nsc.interpreter.IMain$ReadEvalPrint.callEither(IMain.scala:777)
scala.tools.nsc.interpreter.IMain$ReadEvalPrint.evalEither(IMain.scala:792)
scala.tools.nsc.interpreter.IMain$WrappedRequest.eval(IMain.scala:613)
scala.tools.nsc.interpreter.IMain.eval(IMain.scala:1047)
javax.script.AbstractScriptEngine.eval(Unknown Source)
test.Main.main(Main.java:19)
java.lang.Thread.getStackTrace(Unknown Source)
test.Singleton.<init>(Singleton.java:10)
test.Singleton.<clinit>(Singleton.java:7)
test.Main.main(Main.java:20)
堆栈跟踪显示脚本引擎最终创建了 Singleton
的新实例,但我不知道为什么。
谢谢。
浏览源代码后发现修复:
((scala.tools.nsc.interpreter.IMain) engine).settings().embeddedDefaults(Main.class.getClassLoader());
这会将 ScriptEngine
的 ClassLoader
更改为相同的
所以,我正在使用 JSR 223
为 Scala 创建一个脚本系统,但我遇到了这个问题,我找不到任何原因。
有一个类似单例的 class,它具有添加事件侦听器(来自脚本)和调度事件(来自核心)的方法。一切正常,但由于某种原因,当我开始发送事件时,添加的侦听器消失了。
重现问题后发现脚本引擎又创建了一个单例实例:
这是我的 Singleton
class:
package test;
import java.util.Arrays;
public final class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
Arrays.stream(Thread.currentThread().getStackTrace()).forEach(System.out::println);
System.out.println();
}
public static Singleton instance() {
return instance;
}
}
这是我的 Main
class:
package test;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public final class Main {
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("scala");
// this is a trick I found to access the classpath,
// might be the problem
@SuppressWarnings("rawtypes")
scala.collection.immutable.List nil = scala.collection.immutable.Nil$.MODULE$;
@SuppressWarnings("unchecked")
scala.collection.immutable.$colon$colon<String> vals = scala.collection.immutable.$colon$colon$.MODULE$.apply("true", nil);
((scala.tools.nsc.interpreter.IMain) engine).settings().usejavacp().tryToSet(vals);
engine.eval("test.Singleton.instance");
Singleton.instance();
}
}
这是输出:
java.lang.Thread.getStackTrace(Unknown Source)
test.Singleton.<init>(Singleton.java:10)
test.Singleton.<clinit>(Singleton.java:7)
$line3.$read$$iw$$iw$.<init>(<console>:8)
$line3.$read$$iw$$iw$.<clinit>(<console>)
$line3.$eval$.$result$lzycompute(<console>:5)
$line3.$eval$.$result(<console>:5)
$line3.$eval.$result(<console>)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:773)
scala.tools.nsc.interpreter.IMain$ReadEvalPrint.callEither(IMain.scala:777)
scala.tools.nsc.interpreter.IMain$ReadEvalPrint.evalEither(IMain.scala:792)
scala.tools.nsc.interpreter.IMain$WrappedRequest.eval(IMain.scala:613)
scala.tools.nsc.interpreter.IMain.eval(IMain.scala:1047)
javax.script.AbstractScriptEngine.eval(Unknown Source)
test.Main.main(Main.java:19)
java.lang.Thread.getStackTrace(Unknown Source)
test.Singleton.<init>(Singleton.java:10)
test.Singleton.<clinit>(Singleton.java:7)
test.Main.main(Main.java:20)
堆栈跟踪显示脚本引擎最终创建了 Singleton
的新实例,但我不知道为什么。
谢谢。
浏览源代码后发现修复:
((scala.tools.nsc.interpreter.IMain) engine).settings().embeddedDefaults(Main.class.getClassLoader());
这会将 ScriptEngine
的 ClassLoader
更改为相同的