java 在 groovy 中动态加载 jar

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16219805/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 22:16:14  来源:igfitidea点击:

Dynamically load jar in groovy

javagroovyclasspath

提问by rouble

I have a groovy script createWidget.groovy:

我有一个 groovy 脚本 createWidget.groovy:

 import com.example.widget

 Widget w = new Widget()

This script runs great when I run it like this:

当我像这样运行这个脚本时,它运行得很好:

$ groovy -cp /path/to/widget.jar createWidget.groovy

But, I wanted to hardcode the classpath within the script, so that users do not need to know where it is, so I modified createWidget.groovy as follows (which is one of the ways to modify classpath in groovy):

但是,我想在脚本中硬编码类路径,这样用户就不需要知道它在哪里,所以我修改了 createWidget.groovy 如下(这是在 groovy 中修改类路径的方法之一):

this.getClass().classLoader.rootLoader.addURL(new File("/path/to/widget.jar").toURL())

import com.example.widget

Widget w = new Widget()

But this always fails with a runtime error on the import: unable to resolve class com.example.widget.

但这总是失败并在导入时出现运行时错误:unable to resolve class com.example.widget

This does look unorthodox and I am thinking you can't mess with the rootLoader prior to an import or is it something else?

这确实看起来不正统,我认为您不能在导入之前弄乱 rootLoader 还是其他什么?

回答by Bae Cheol Shin

// Use the groovy script's classLoader to add the jar file at runtime.
this.class.classLoader.rootLoader.addURL(new URL("/path/to/widget.jar"));

// Note: if widget.jar file is located in your local machine, use following:
// def localFile = new File("/path/tolocal/widget.jar");
// this.class.classLoader.rootLoader.addURL(localFile.toURI().toURL());

// Then, use Class.forName to load the class.
def cls = Class.forName("com.example.widget").newInstance();

回答by snoop

The other way can be to just write down the java code to load class from jar file and as per groovy modify that code.

另一种方法可以是只写下 java 代码来从 jar 文件加载类,然后根据 groovy 修改该代码。

import java.net.URL;
import java.net.URLClassLoader;
import java.lang.reflect.Method;
public class JarFileLoader 
{
    public static void main (def args)
    {
        try
        {
            URLClassLoader cl = new URLClassLoader (new URL("jar:file:///path/to/widget.jar!/"));

            System.out.println ("Attempting...");

            Class beanClass = cl.loadClass ("com.example.widget.WidgetClass");
            Object dog = beanClass.newInstance();

            Method method = beanClass.getDeclaredMethod ("setBean", String.class);
            method.invoke (dog, "Who let the dog out");

            method = beanClass.getDeclaredMethod("getBean", null);            
            Object retObj = method.invoke (dog, null);

            String retVal = (String)retObj;

            System.out.println(retVal);
            System.out.println("Success!");
        }
        catch (Exception ex)
        {
            System.out.println ("Failed.");
            ex.printStackTrace ();
        }
    }
}

回答by Michael Easter

If I understand the question, then you're asking for a self-contained unit which can be delivered to users.

如果我理解这个问题,那么您是在要求一个可以交付给用户的独立单元。

This is possible using the basics of 'jar' on the JVM.

这可以使用 JVM 上的“jar”基础知识来实现​​。

For example, this projectplays a simple game called War-O. Users can run it with this command:

例如,这个项目玩了一个叫做 War-O 的简单游戏。用户可以使用以下命令运行它:

java -jar warO.jar [args]

The technique includes: (a) compile Groovy to class files and (b) include all necessary jars in the jar (including groovy-all). Also, the jar must have the "main" entry point specified in the manifest (which would be a modified version of your script).

该技术包括:(a) 将 Groovy 编译为类文件和 (b) 在 jar 中包含所有必需的 jar(包括 groovy-all)。此外,jar 必须具有在清单中指定的“主”入口点(这将是脚本的修改版本)。

The War-O project uses Gradle (see build file here), but the principle applies even if using Ant, Maven, etc. Using Gradle as an example:

War-O 项目使用 Gradle(请参阅此处的构建文件),但即使使用 Ant、Maven 等,该原则也适用。以 Gradle 为例:

jar.archiveName 'warO.jar'
jar.manifest {
    attributes 'Main-Class' : 'net.codetojoy.waro.Main'
    attributes 'Class-Path' : 'jars/groovy-all-1.6.4.jar jars/guava-collections-r03.jar jars/guava-base-r03.jar'
}

回答by Peter Niederwieser

Groovy is a compiled language, and class names must be resolvable at compile time. Hence adding the Jar at runtime is not sufficient here.

Groovy 是一种编译语言,类名在编译时必须是可解析的。因此,在运行时添加 Jar 是不够的。

(The import statement is also wrong, you'd have to append .*or .Widget. But this won't solve the deeper problem.)

(import 语句也是错误的,您必须附加.*.Widget。但这并不能解决更深层次的问题。)