无法解决 class 在 Wildfly 中使用 Camel CDI 在 Java 中执行 Grrovy 脚本的问题
unable to resolve class issue with Executing Grrovy Scripts in Java in Wildfly with Camel CDI
背景:
我正在使用 GrrovyShell 调用一个 Groovy 脚本。
@GET
@Path("/endpoint/{param}")
public Response getEndpointService(@PathParam("param") String messageId) {
String scriptPath = "/path/to/Grrovyfile.gsh";
Binding binding = new Binding();
binding.setProperty("in", inParams);
GroovyShell shell = new GroovyShell(binding);
shell.evaluate(new File(scriptPath));
}
Groovy 脚本文件:
def condition = "good"
def severity = "N/A"
def detail = ""
import net.sf.json.JSONObject
import java.util.Random
try{
def detailMap = [
condition: condition,
success: false,
severity: severity,
]
JSONObject jsonObject = JSONObject.fromObject(detailMap)
detail = jsonObject.toString()
}
在这个 war 中有一个单独的 camel 路由器实现,它是用 camel cdi 初始化的。
import javax.enterprise.context.ApplicationScoped;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.cdi.ContextName;
@ApplicationScoped
@ContextName("camel-cdi-context")
public class MiscRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
// router dsl
}
}
问题:
当使用 camel cdi 启动路由器时,上述 groovy 代码失败并出现以下错误。但是当注释 @ApplicationScoped
、@ContextName("camel-cdi-context")
行时成功且没有错误。
12:47:28,108 ERROR [stderr] (default task-11) org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
12:47:28,109 ERROR [stderr] (default task-11) /path/to/Grrovyfile.gsh: 9: unable to resolve class net.sf.json.JSONObject
12:47:28,109 ERROR [stderr] (default task-11) @ line 9, column 1.
12:47:28,109 ERROR [stderr] (default task-11) import net.sf.json.JSONObject
12:47:28,109 ERROR [stderr] (default task-11) ^
12:47:28,109 ERROR [stderr] (default task-11)
12:47:28,109 ERROR [stderr] (default task-11) 1 error
12:47:28,109 ERROR [stderr] (default task-11)
12:47:28,110 ERROR [stderr] (default task-11) at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
12:47:28,110 ERROR [stderr] (default task-11) at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:958)
12:47:28,110 ERROR [stderr] (default task-11) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:605)
12:47:28,113 ERROR [stderr] (default task-11) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:554)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:584)
12:47:28,114 ERROR [stderr] (default task-11) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:632)
12:47:28,114 ERROR [stderr] (default task-11) at TestGroovy.getEndpointService(TestGroovy.java:91)
12:47:28,114 ERROR [stderr] (default task-11) at org.jboss.weld.proxies.TestGroovy$Proxy$_$$_WeldClientProxy.getEndpointService(Unknown Source)
我认为这是一个 class 加载问题,我正在尝试解决这个问题。在这里期待一点帮助。
已经尝试过:
- 使用 jboss-deployment-structure.xml.
将这些依赖 jar 作为模块提供
- 在
CompilerConfiguration
中使用 ImportCustomizer
向 GroovyShell
提供导入
- 也尝试使用 Startup Singleton EJB 加载它。
- 尝试使用单独的注入加载它
- 试图在单独的静态中加载 JSONObject class
注:
- 请注意,相关的 jar 已经在 war 文件中 (WEB-INF/lib)。
- 其他第三方工件也会出现同样的问题,例如
com.fasterxml.jackson.databind.node.ObjectNode
、com.fasterxml.jackson.databind.ObjectMapper
。
- 但是像
org.apache.log4j.Logger
这样的第三方工件不会发生这个问题。 (可能它们已经通过 wildfly 加载了)
更新:
当 JVM 启动时,根据 forums / artiles classLoader returns 类路径上的所有 class,我离 answer.As 更近了一步.
因此,我尝试手动添加相关工件并使用 classloader 而不是 GroovyShell 调用脚本。它奏效了!现在需要找到一种方法在 JVM 启动时将这些 classes 加载到这些工件中/将它们添加到 wildfly 中的 class 路径。
URL[] classLoaderUrls = new URL[] {
new URL("file:///path/to/repo/net/sf/json-lib/json-lib/2.4/json-lib-2.4-jdk15.jar"),
new URL("file:///path/to/repo/commons-beanutils-1.8.0.jar"),
new URL("file:///path/to/repo/commons-collections-3.2.1.jar"),
new URL("file:///path/to/repo/commons-lang-2.5.jar"),
new URL("file:///path/to/repo/commons-logging-1.1.1.jar"),
new URL("file:///path/to/repo/groovy-all-2.4.11.jar"),
new URL("file:///path/to/repo/net/sf/json/main/ezmorph-1.0.6.jar") };
URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls);
//GroovyClassLoader groovyClassLoader = new GroovyClassLoader(urlClassLoader);
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Script script = InvokerHelper.createScript(groovyClassLoader.parseClass(new
File(scripts)), binding);
System.out.println("getEndpointService().script : " + script);
Object responseObj = script.run();
版本:
- Wildfly 版本:10.1.0
- Wildfly Camle 补丁:4.9.0
- Groovy 版本:groovy-all-2.4.7
我自己找到了答案。
当您使用 GroovyClassLoader 而不是 GroovyShell 时,可以解决此问题。实际上,我通过反编译深入研究了 GroovyShell,我看到它也在那里使用。
注意:如果类路径中的 jars 不需要像上面提到的那样使用 URLClassLoader 手动导入它们 post.
所以通过下面的实现,它现在可以正常工作了。
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Script script = InvokerHelper.createScript(groovyClassLoader.parseClass(new
File(scriptPath)), binding);
logger.info("getEndpointService().script : " + script);
Object responseObj = script.run();
logger.info("getEndpointService().responseObj : " + responseObj);
此外,如果您需要像其他属性一样使用 codeBase,您也可以使用 GroovyCodeSource。
GroovyCodeSource groovyCodeSource = new GroovyCodeSource(new File(scriptPath));
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Script script = InvokerHelper.createScript(groovyClassLoader.parseClass(groovyCodeSource), binding);
logger.info("getEndpointService().script : " + script);
Object responseObj = script.run();
logger.info("getEndpointService().responseObj : " + responseObj);
背景:
我正在使用 GrrovyShell 调用一个 Groovy 脚本。
@GET
@Path("/endpoint/{param}")
public Response getEndpointService(@PathParam("param") String messageId) {
String scriptPath = "/path/to/Grrovyfile.gsh";
Binding binding = new Binding();
binding.setProperty("in", inParams);
GroovyShell shell = new GroovyShell(binding);
shell.evaluate(new File(scriptPath));
}
Groovy 脚本文件:
def condition = "good"
def severity = "N/A"
def detail = ""
import net.sf.json.JSONObject
import java.util.Random
try{
def detailMap = [
condition: condition,
success: false,
severity: severity,
]
JSONObject jsonObject = JSONObject.fromObject(detailMap)
detail = jsonObject.toString()
}
在这个 war 中有一个单独的 camel 路由器实现,它是用 camel cdi 初始化的。
import javax.enterprise.context.ApplicationScoped;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.cdi.ContextName;
@ApplicationScoped
@ContextName("camel-cdi-context")
public class MiscRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
// router dsl
}
}
问题:
当使用 camel cdi 启动路由器时,上述 groovy 代码失败并出现以下错误。但是当注释 @ApplicationScoped
、@ContextName("camel-cdi-context")
行时成功且没有错误。
12:47:28,108 ERROR [stderr] (default task-11) org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
12:47:28,109 ERROR [stderr] (default task-11) /path/to/Grrovyfile.gsh: 9: unable to resolve class net.sf.json.JSONObject
12:47:28,109 ERROR [stderr] (default task-11) @ line 9, column 1.
12:47:28,109 ERROR [stderr] (default task-11) import net.sf.json.JSONObject
12:47:28,109 ERROR [stderr] (default task-11) ^
12:47:28,109 ERROR [stderr] (default task-11)
12:47:28,109 ERROR [stderr] (default task-11) 1 error
12:47:28,109 ERROR [stderr] (default task-11)
12:47:28,110 ERROR [stderr] (default task-11) at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
12:47:28,110 ERROR [stderr] (default task-11) at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:958)
12:47:28,110 ERROR [stderr] (default task-11) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:605)
12:47:28,113 ERROR [stderr] (default task-11) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:554)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
12:47:28,113 ERROR [stderr] (default task-11) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:584)
12:47:28,114 ERROR [stderr] (default task-11) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:632)
12:47:28,114 ERROR [stderr] (default task-11) at TestGroovy.getEndpointService(TestGroovy.java:91)
12:47:28,114 ERROR [stderr] (default task-11) at org.jboss.weld.proxies.TestGroovy$Proxy$_$$_WeldClientProxy.getEndpointService(Unknown Source)
我认为这是一个 class 加载问题,我正在尝试解决这个问题。在这里期待一点帮助。
已经尝试过:
- 使用 jboss-deployment-structure.xml. 将这些依赖 jar 作为模块提供
- 在
CompilerConfiguration
中使用 - 也尝试使用 Startup Singleton EJB 加载它。
- 尝试使用单独的注入加载它
- 试图在单独的静态中加载 JSONObject class
ImportCustomizer
向 GroovyShell
提供导入
注:
- 请注意,相关的 jar 已经在 war 文件中 (WEB-INF/lib)。
- 其他第三方工件也会出现同样的问题,例如
com.fasterxml.jackson.databind.node.ObjectNode
、com.fasterxml.jackson.databind.ObjectMapper
。 - 但是像
org.apache.log4j.Logger
这样的第三方工件不会发生这个问题。 (可能它们已经通过 wildfly 加载了)
更新:
当 JVM 启动时,根据 forums / artiles classLoader returns 类路径上的所有 class,我离 answer.As 更近了一步.
因此,我尝试手动添加相关工件并使用 classloader 而不是 GroovyShell 调用脚本。它奏效了!现在需要找到一种方法在 JVM 启动时将这些 classes 加载到这些工件中/将它们添加到 wildfly 中的 class 路径。
URL[] classLoaderUrls = new URL[] {
new URL("file:///path/to/repo/net/sf/json-lib/json-lib/2.4/json-lib-2.4-jdk15.jar"),
new URL("file:///path/to/repo/commons-beanutils-1.8.0.jar"),
new URL("file:///path/to/repo/commons-collections-3.2.1.jar"),
new URL("file:///path/to/repo/commons-lang-2.5.jar"),
new URL("file:///path/to/repo/commons-logging-1.1.1.jar"),
new URL("file:///path/to/repo/groovy-all-2.4.11.jar"),
new URL("file:///path/to/repo/net/sf/json/main/ezmorph-1.0.6.jar") };
URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls);
//GroovyClassLoader groovyClassLoader = new GroovyClassLoader(urlClassLoader);
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Script script = InvokerHelper.createScript(groovyClassLoader.parseClass(new
File(scripts)), binding);
System.out.println("getEndpointService().script : " + script);
Object responseObj = script.run();
版本:
- Wildfly 版本:10.1.0
- Wildfly Camle 补丁:4.9.0
- Groovy 版本:groovy-all-2.4.7
我自己找到了答案。
当您使用 GroovyClassLoader 而不是 GroovyShell 时,可以解决此问题。实际上,我通过反编译深入研究了 GroovyShell,我看到它也在那里使用。
注意:如果类路径中的 jars 不需要像上面提到的那样使用 URLClassLoader 手动导入它们 post.
所以通过下面的实现,它现在可以正常工作了。
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Script script = InvokerHelper.createScript(groovyClassLoader.parseClass(new
File(scriptPath)), binding);
logger.info("getEndpointService().script : " + script);
Object responseObj = script.run();
logger.info("getEndpointService().responseObj : " + responseObj);
此外,如果您需要像其他属性一样使用 codeBase,您也可以使用 GroovyCodeSource。
GroovyCodeSource groovyCodeSource = new GroovyCodeSource(new File(scriptPath));
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Script script = InvokerHelper.createScript(groovyClassLoader.parseClass(groovyCodeSource), binding);
logger.info("getEndpointService().script : " + script);
Object responseObj = script.run();
logger.info("getEndpointService().responseObj : " + responseObj);