Java GroovyClassLoader-与父类装入器隔离
我试图使用Java GroovyClassLoader-与父类装入器隔离,java,groovy,classloader,Java,Groovy,Classloader,我试图使用GroovyClassLoader和GroovyScriptEngineImpl在我的Java应用程序中运行Groovy脚本,我想将Groovy脚本与父应用程序上下文隔离开来 我的意思是,当我运行Groovy脚本时,我不希望它继承Java应用程序中加载的依赖项,以便能够在脚本中加载Gson 2.5.5,即使Java应用程序正在使用Gson 3.4.1 // Replacing the context class loader with the system one ClassLoade
GroovyClassLoader
和GroovyScriptEngineImpl
在我的Java应用程序中运行Groovy脚本,我想将Groovy脚本与父应用程序上下文隔离开来
我的意思是,当我运行Groovy脚本时,我不希望它继承Java应用程序中加载的依赖项,以便能够在脚本中加载Gson 2.5.5
,即使Java应用程序正在使用Gson 3.4.1
// Replacing the context class loader with the system one
ClassLoader initialCL = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader().getParent());
// Creating my GroovyClassLoader and GroovyScriptEngine
GroovyClassLoader groovyCL = new GroovyClassLoader();
GroovyScriptEngineImpl scriptEngine = new GroovyScriptEngineImpl(groovyCL);
// Compiling and running my Groovy script
CompiledScript compiledScript = scriptEngine.compile("println \"hello\"");
compiledScript.eval();
// Going back to my initial classloader
Thread.currentThread().setContextClassLoader(initialCL);
这样,隔离确实起作用了,但是脚本的内容根本没有被执行(例如,甚至在控制台中打印一行),并且我没有发现任何错误
如果在创建新的GroovyClassLoader
之前不更新上下文类加载器,脚本工作正常,但它是从父依赖项继承的
你知道吗
谢谢:)
更新:经过一点测试后,编译似乎工作正常,但对编译脚本的评估没有任何作用。事实上,我在尝试编译一个脚本时遇到了一个错误,该脚本没有所需的所有依赖项,即使它们存在于我的Java应用程序类路径中。好的,终于找到了答案,这是一个有趣的问题 我说没有错误,虽然没有打印,但实际上我有一个错误(很明显,因为它不工作…)。我通过使用
GroovyShell
而不是GroovyScriptEngineImpl
和GroovyClassLoader
略微更改执行Groovy脚本的方法,成功地获得了错误:
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader().getParent());
GroovyClassLoader groovyCL = new GroovyClassLoader();
new GroovyShell(groovyCL).evaluate("println(\"test\")");
这是我最终得到的错误,由于某种原因,它在我以前的执行过程中隐藏了,没有使用GroovyShell
:
groovy.lang.GroovyRuntimeException: Failed to create Script instance for class: class Script1. Reason: java.lang.ClassCastException: Script1 cannot be cast to groovy.lang.GroovyObject
那有什么问题? 实际上,用于编译脚本的类加载器和用于评估编译脚本的类加载器并不相同:
groovyCL
用于编译脚本,“当前线程”类加载器用于创建GroovyShell
对象并评估脚本
这意味着来自两个类加载器的groovy.lang.GroovyObject
不兼容,因为类是在两个类加载器中定义的(即使它们在代码上完全相同)
然后,当试图强制转换由groovyCL
创建的Script1
对象时,GroovyShell
(或者我之前使用的groovyscript引擎eimpl
等的机制)将遇到ClassCastException
这整件事可能会导致有趣的错误,例如:
java.lang.ClassCastException: groovy.lang.GroovyShell cannot be cast to groovy.lang.GroovyShell
解决方案 因此,您要做的是创建
GroovyClassLoader
实例,并使用这个类加载器,使用反射创建工作流的所有对象:
GroovyClassLoader groovyCL = new GroovyClassLoader();
Class groovyShellClazz = groovyCL.loadClass(GroovyShell.class.getName());
Object groovyShellObj = groovyShellClazz.newInstance();
Method evaluateMethod = groovyShellClazz.getMethod("evaluate", String.class);
evaluateMethod.invoke(groovyShellObj, "println(\"test\")");
这需要更多的工作,但是脚本将由同一个类加载器编译和评估,问题将得到解决
我仍然需要使用GroovyScriptEngineImpl
使此解决方案适应我的初始情况,但它是完全相同的方法:)