是否可以“添加” java中动态的类路径?

发布于 2024-07-10 05:44:42 字数 476 浏览 9 评论 0原文

java -classpath ../classes;../jar;. parserTester

如何以编程方式获取上述命令中的功能? 比如,是否可以运行为:

java parserTester

并得到相同的结果? 我尝试使用 URLClassLoader 但它修改了类路径并且没有添加到它。

谢谢!


感谢米尔豪斯的回复。 但这就是我想要做的。如何才能首先将 jar 放入类路径中? 我也尝试使用自定义类加载器:(

这有效..但抱歉我只需要运行它: java解析器测试器 我想知道这样的事情是否可能???

它需要如此,因为我有 parserTester.java 和 .class 在一个单独的文件夹中。 我需要保留文件结构。 parserTester 使用单独的 jar 文件夹中的 jar。

java -classpath ../classes;../jar;. parserTester

How can i get the functionality in the above command programmatically? Like, is it possible to run as:

java parserTester

and get the same result? I tried using URLClassLoader but it modifies the classpath and does not add to it.

Thanx!


Thanks for the response Milhous. But that is what i am trying to do.. How is it possible to get the jar into the classpath first? I tried using a custom classloader too :(

That works.. But sorry that i need to run it only as:
java parserTester
I would like to know if such a thing is possible???

It needs to be so bcoz i have parserTester.java and .class in a separate folder. I need to retain the file structure. The parserTester makes use of a jar in a separate jar folder.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

喜爱纠缠 2024-07-17 05:44:42

您可以使用 java.net.URLClassLoader 来加载具有您希望的任何程序定义的 URL 列表的类:

公共类 URLClassLoader
扩展 SecureClassLoader

该类加载器用于加载
搜索中的类和资源
引用两个 JAR 的 URL 路径
文件和目录。 任何网址
以“/”结尾的被假定为引用
一个目录。 否则,URL 为
假设引用一个 JAR 文件
将根据需要打开。

线程的AccessControlContext
创建了实例
URLClassLoader 将在以下情况下使用
随后加载类和
资源。

加载的类是
默认仅授予权限
访问指定的 URL
URLClassLoader 已创建。

自:
1.2

一些花哨的步骤可以扩展它以支持使用通配符路径名来获取 JAR 的整个目录(此代码有一些对实用程序方法的引用,但它们的实现在上下文中应该是显而易见的):

/**
 * Add classPath to this loader's classpath.
 * <p>
 * The classpath may contain elements that include a generic file base name.  A generic basename
 * is a filename without the extension that may begin and/or end with an asterisk.  Use of the
 * asterisk denotes a partial match. Any files with an extension of ".jar" whose base name match
 * the specified basename will be added to this class loaders classpath.  The case of the filename is ignored.
 * For example "/somedir/*abc" means all files in somedir that end with "abc.jar", "/somedir/abc*"
 * means all files that start with "abc" and end with ".jar", and "/somedir/*abc*" means all files
 * that contain "abc" and end with ".jar".
 *
 */
public void addClassPath(String cp) {
    String                              seps=File.pathSeparator;                // separators

    if(!File.pathSeparator.equals(";")) { seps+=";"; }                          // want to accept both system separator and ';'
    for(StringTokenizer st=new StringTokenizer(cp,seps,false); st.hasMoreTokens(); ) {
        String pe=st.nextToken();
        File   fe;
        String bn=null;

        if(pe.length()==0) { continue; }

        fe=new File(pe);
        if(fe.getName().indexOf('*')!=-1) {
            bn=fe.getName();
            fe=fe.getParentFile();
            }

        if(!fe.isAbsolute() && pe.charAt(0)!='/' && pe.charAt(0)!='\\') { fe=new File(rootPath,fe.getPath()); }
        try { fe=fe.getCanonicalFile(); }
        catch(IOException thr) {
            log.diagln("Skipping non-existent classpath element '"+fe+"' ("+thr+").");
            continue;
            }
        if(!GenUtil.isBlank(bn)) {
            fe=new File(fe,bn);
            }
        if(classPathElements.contains(fe.getPath())) {
            log.diagln("Skipping duplicate classpath element '"+fe+"'.");
            continue;
            }
        else {
            classPathElements.add(fe.getPath());
            }

        if(!GenUtil.isBlank(bn)) {
            addJars(fe.getParentFile(),bn);
            }
        else if(!fe.exists()) {                                                 // s/never be due getCanonicalFile() above
            log.diagln("Could not find classpath element '"+fe+"'");
            }
        else if(fe.isDirectory()) {
            addURL(createUrl(fe));
            }
        else if(fe.getName().toLowerCase().endsWith(".zip") || fe.getName().toLowerCase().endsWith(".jar")) {
            addURL(createUrl(fe));
            }
        else {
            log.diagln("ClassPath element '"+fe+"' is not an existing directory and is not a file ending with '.zip' or '.jar'");
            }
        }
    log.diagln("Class loader is using classpath: \""+classPath+"\".");
    }

/**
 * Adds a set of JAR files using a generic base name to this loader's classpath.  See @link:addClassPath(String) for
 * details of the generic base name.
 */
public void addJars(File dir, String nam) {
    String[]                            jars;                                   // matching jar files

    if(nam.endsWith(".jar")) { nam=nam.substring(0,(nam.length()-4)); }

    if(!dir.exists()) {
        log.diagln("Could not find directory for Class Path element '"+dir+File.separator+nam+".jar'");
        return;
        }
    if(!dir.canRead()) {
        log.error("Could not read directory for Class Path element '"+dir+File.separator+nam+".jar'");
        return;
        }

    FileSelector fs=new FileSelector(true).add("BaseName","EG",nam,true).add("Name","EW",".jar",true);
    if((jars=dir.list(fs))==null) {
        log.error("Error accessing directory for Class Path element '"+dir+File.separator+nam+".jar'");
        }
    else if(jars.length==0) {
        log.diagln("No JAR files match specification '"+new File(dir,nam)+".jar'");
        }
    else {
        log.diagln("Adding files matching specification '"+dir+File.separator+nam+".jar'");
        Arrays.sort(jars,String.CASE_INSENSITIVE_ORDER);
        for(int xa=0; xa<jars.length; xa++) { addURL(createUrl(new File(dir,jars[xa]))); }
        }
    }

private URL createUrl(File fe) {
    try {
        URL url=fe.toURI().toURL();
        log.diagln("Added URL: '"+url.toString()+"'");
        if(classPath.length()>0) { classPath+=File.pathSeparator; }
        this.classPath+=fe.getPath();
        return url;
        }
    catch(MalformedURLException thr) {
        log.diagln("Classpath element '"+fe+"' could not be used to create a valid file system URL");
        return null;
        }
    }

You can use a java.net.URLClassLoader to load classes with any program defined list of URL's you wish:

public class URLClassLoader
extends SecureClassLoader

This class loader is used to load
classes and resources from a search
path of URLs referring to both JAR
files and directories. Any URL that
ends with a '/' is assumed to refer to
a directory. Otherwise, the URL is
assumed to refer to a JAR file which
will be opened as needed.

The AccessControlContext of the thread
that created the instance of
URLClassLoader will be used when
subsequently loading classes and
resources.

The classes that are loaded are by
default granted permission only to
access the URLs specified when the
URLClassLoader was created.

Since:
1.2

And a little fancy footwork can extend it to support using wildcarded pathnames to pick up entire directories of JARs (this code has some references to utility methods, but their implementation should be obvious in the context):

/**
 * Add classPath to this loader's classpath.
 * <p>
 * The classpath may contain elements that include a generic file base name.  A generic basename
 * is a filename without the extension that may begin and/or end with an asterisk.  Use of the
 * asterisk denotes a partial match. Any files with an extension of ".jar" whose base name match
 * the specified basename will be added to this class loaders classpath.  The case of the filename is ignored.
 * For example "/somedir/*abc" means all files in somedir that end with "abc.jar", "/somedir/abc*"
 * means all files that start with "abc" and end with ".jar", and "/somedir/*abc*" means all files
 * that contain "abc" and end with ".jar".
 *
 */
public void addClassPath(String cp) {
    String                              seps=File.pathSeparator;                // separators

    if(!File.pathSeparator.equals(";")) { seps+=";"; }                          // want to accept both system separator and ';'
    for(StringTokenizer st=new StringTokenizer(cp,seps,false); st.hasMoreTokens(); ) {
        String pe=st.nextToken();
        File   fe;
        String bn=null;

        if(pe.length()==0) { continue; }

        fe=new File(pe);
        if(fe.getName().indexOf('*')!=-1) {
            bn=fe.getName();
            fe=fe.getParentFile();
            }

        if(!fe.isAbsolute() && pe.charAt(0)!='/' && pe.charAt(0)!='\\') { fe=new File(rootPath,fe.getPath()); }
        try { fe=fe.getCanonicalFile(); }
        catch(IOException thr) {
            log.diagln("Skipping non-existent classpath element '"+fe+"' ("+thr+").");
            continue;
            }
        if(!GenUtil.isBlank(bn)) {
            fe=new File(fe,bn);
            }
        if(classPathElements.contains(fe.getPath())) {
            log.diagln("Skipping duplicate classpath element '"+fe+"'.");
            continue;
            }
        else {
            classPathElements.add(fe.getPath());
            }

        if(!GenUtil.isBlank(bn)) {
            addJars(fe.getParentFile(),bn);
            }
        else if(!fe.exists()) {                                                 // s/never be due getCanonicalFile() above
            log.diagln("Could not find classpath element '"+fe+"'");
            }
        else if(fe.isDirectory()) {
            addURL(createUrl(fe));
            }
        else if(fe.getName().toLowerCase().endsWith(".zip") || fe.getName().toLowerCase().endsWith(".jar")) {
            addURL(createUrl(fe));
            }
        else {
            log.diagln("ClassPath element '"+fe+"' is not an existing directory and is not a file ending with '.zip' or '.jar'");
            }
        }
    log.diagln("Class loader is using classpath: \""+classPath+"\".");
    }

/**
 * Adds a set of JAR files using a generic base name to this loader's classpath.  See @link:addClassPath(String) for
 * details of the generic base name.
 */
public void addJars(File dir, String nam) {
    String[]                            jars;                                   // matching jar files

    if(nam.endsWith(".jar")) { nam=nam.substring(0,(nam.length()-4)); }

    if(!dir.exists()) {
        log.diagln("Could not find directory for Class Path element '"+dir+File.separator+nam+".jar'");
        return;
        }
    if(!dir.canRead()) {
        log.error("Could not read directory for Class Path element '"+dir+File.separator+nam+".jar'");
        return;
        }

    FileSelector fs=new FileSelector(true).add("BaseName","EG",nam,true).add("Name","EW",".jar",true);
    if((jars=dir.list(fs))==null) {
        log.error("Error accessing directory for Class Path element '"+dir+File.separator+nam+".jar'");
        }
    else if(jars.length==0) {
        log.diagln("No JAR files match specification '"+new File(dir,nam)+".jar'");
        }
    else {
        log.diagln("Adding files matching specification '"+dir+File.separator+nam+".jar'");
        Arrays.sort(jars,String.CASE_INSENSITIVE_ORDER);
        for(int xa=0; xa<jars.length; xa++) { addURL(createUrl(new File(dir,jars[xa]))); }
        }
    }

private URL createUrl(File fe) {
    try {
        URL url=fe.toURI().toURL();
        log.diagln("Added URL: '"+url.toString()+"'");
        if(classPath.length()>0) { classPath+=File.pathSeparator; }
        this.classPath+=fe.getPath();
        return url;
        }
    catch(MalformedURLException thr) {
        log.diagln("Classpath element '"+fe+"' could not be used to create a valid file system URL");
        return null;
        }
    }
白衬杉格子梦 2024-07-17 05:44:42

我必须同意其他两个海报,听起来你使测试类过于复杂化。
将 .java 和 .class 文件放在不同的文件夹中,而依赖第三个文件夹中的 jar 文件,而无需以编程方式更改类路径的情况并不罕见。
如果您这样做是因为您不想每次都在命令行上键入类路径,我建议您使用 shell 脚本或批处理文件。 更好的是,一个 IDE。
我真正的问题是你为什么要尝试在代码中管理类路径?

I have to agree with the other two posters, it sounds like you're overcomplicating a test class.
It's not that unusual to have the .java and .class files in separate folders, while depending on jar files in yet a third, without programmatically changing the classpath.
If you're doing it because you don't want to have to type the classpath on the command line everytime, I would suggest a shell script or batch file. Better yet, an IDE.
The question I really have is why are you doing trying to manage the classpath in code?

怎会甘心 2024-07-17 05:44:42

您可以实现自己的类加载器,但该类/jar 必须位于类路径中才能执行。

尝试

java -cp *.jar:. myClass

export CLASSPATH=./lib/tool.jar:.
java myClass

java -jar file.jar

You could implement your own class loader, but that class/jar has to be in the classpath for it to be executed.

try

java -cp *.jar:. myClass

or

export CLASSPATH=./lib/tool.jar:.
java myClass

or

java -jar file.jar
停顿的约定 2024-07-17 05:44:42

您可以编写批处理文件或shell脚本文件来导出类路径并运行java程序。
在 Windows 中,

设置 classpath=%classpath%;../classes;../jars/*
java ParserTester

在 Unix 中,
导出类路径=%classpath%:../classes:../jars/*
java ParserTester

如果您将文件名命名为 parser.bat 或 parser.sh,则可以通过在相应操作系统中调用 parser 来运行它。

从 java 1.6 开始,您可以通过以下命令将目录中的所有 jar 包含到类路径中: /*

如果您尝试动态生成 java 文件,请编译并添加到类路径中,设置生成类文件的目录预先的类路径。 它应该加载该类。
如果你正在修改已经生成的java类,基本上修改后重新编译,如果你想加载新的类,你需要使用自定义类加载器来避免类的缓存。

You can write a batch file or shell script file to export the classpath and run the java program.
In Windows,

set classpath=%classpath%;../classes;../jars/*
java ParserTester

In Unix,
export classpath=%classpath%:../classes:../jars/*
java ParserTester

If you name the file name as parser.bat or parser.sh, you can just run that by calling parser in respective OS.

From java 1.6, you can include all the jars in a directory into the classpath just by saying /*

If you are trying to generate a java file dynamically, compile and add into the classpath, set the directory into which the class file gets generated in the classpath beforehand. It should load the class.
If you are modifying the already generated java class, basically recompiling after modification and if you want to load the new class, you need to use your custom class loader to avoid the caching of the class.

挽容 2024-07-17 05:44:42

我认为您想要的是一个“执行包装器”或特定于平台的“启动器”...通常该组件用于检测您的操作系统、体系结构和依赖项,然后在启动应用程序之前进行调整。 这是一种老式的设计模式(80 年代及更早的版本),但至今仍被广泛使用。 这个想法是,您的程序可以与系统和环境无关,启动器将做好准备并告诉软件它需要知道的一切。 许多现代开源程序使用 Shell 脚本和批处理文件等来执行此操作...例如 Apache Tomcat。 您可以轻松地用 java 制作包装器,并使用命令行 exec 启动软件(请务必在 *NIX 中的 exec 命令末尾添加“&”,以便您的包装器可以退出,只留下您的软件运行...还可以让您关闭 shell 窗口而不终止进程)

I think what you want is an "Execution Wrapper" or a platform specific "Launcher"... typically this component is used to detect your OS and architecture and dependencies and then makes adjustments before launching your application. It is an old school design pattern (talking 80's and earlier) but is still used a lot today. The idea is that you program can be system and environment agnostic and the launcher will make preparations and tell the software everything it needs to know. Many modern open source programs do this with Shell scripts and Batch Files, etc... Apache Tomcat for example. You could just as easily make the wrapper in java an have it launch the software with a command line exec (be sure to add " &" to the end of you exec command in *NIX so your wrapper can exit leaving only your software running... also lets you close the shell window without killing the process)

泅渡 2024-07-17 05:44:42

我没理解错吧?! 您拥有它的唯一原因是您想要在不指定类路径的情况下启动类并在运行时加载它? ...

java解析器测试器

而不是

java -classpath ../classes;../jar;. 解析器测试器

可能我没有明白你的原因。 但是,如果“这就是”您想要的,您可以执行以下操作(尽管这对我来说没有多大意义)

  • 启动类
  • 从 main 方法启动另一个类,以编程方式在那里设置类路径。
  • 历史的终结。

类似下面的“java -伪代码”

public static void main( String [] args ) {
    String classpath = "classes;../jar";
    Runtime.getRuntime().execute("java + classpath + " parserTester ");
}

请告诉我我是否正确。 如果您想做其他事情,我很乐意提供帮助。

Did I understand right?! The only reason you have it that you want to launch your class without specifying the classpath and load it at runtime? ...

java parserTester

instead of

java -classpath ../classes;../jar;. parserTester

Probably I didn't get your reason. But if "that's" what you want you can do the following ( although it does not make much sense to me )

  • Launch the class
  • From the main method lauch another class an programatically set the classpath there.
  • End of history.

Something like the following "java -pseudo code "

public static void main( String [] args ) {
    String classpath = "classes;../jar";
    Runtime.getRuntime().execute("java + classpath + " parserTester ");
}

Please tell me if I get it right. If you want to do something else I would gladly help.

猫九 2024-07-17 05:44:42

非常好的帖子,就我而言,我这样做效果很好(注意:Windows 特定):

set classpath=%classpath%;../lib/*
java -cp %classpath% com.test.MyClass 

Excellent good post, in my case I did this to work well (note: Windows specific):

set classpath=%classpath%;../lib/*
java -cp %classpath% com.test.MyClass 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文