简体   繁体   English

是否可以在Java中动态“添加”到类路径?

[英]Is it possible to “add” to classpath dynamically in java?

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. 我尝试使用URLClassLoader,但它修改了类路径,并且没有添加到它。

Thanx! 谢谢!


Thanks for the response Milhous. 感谢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??? 那行得通。。但是很抱歉,我只需要以以下方式运行它:java parserTester我想知道这样的事情是否可能???

It needs to be so bcoz i have parserTester.java and .class in a separate folder. 需要这样,因为我在单独的文件夹中有parserTester.java和.class。 I need to retain the file structure. 我需要保留文件结构。 The parserTester makes use of a jar in a separate jar folder. parserTester在单独的jar文件夹中使用jar。

You can use a java.net.URLClassLoader to load classes with any program defined list of URL's you wish: 您可以使用java.net.URLClassLoader来加载具有您希望的任何URL的程序定义列表的类:

public class URLClassLoader extends SecureClassLoader 公共类URLClassLoader扩展了SecureClassLoader

This class loader is used to load classes and resources from a search path of URLs referring to both JAR files and directories. 该类加载器用于从同时引用JAR文件和目录的URL的搜索路径中加载类和资源。 Any URL that ends with a '/' is assumed to refer to a directory. 假定任何以“ /”结尾的URL均指向目录。 Otherwise, the URL is assumed to refer to a JAR file which will be opened as needed. 否则,假定该URL引用将根据需要打开的JAR文件。

The AccessControlContext of the thread that created the instance of URLClassLoader will be used when subsequently loading classes and resources. 随后加载类和资源时,将使用创建URLClassLoader实例的线程的AccessControlContext。

The classes that are loaded are by default granted permission only to access the URLs specified when the URLClassLoader was created. 默认情况下,仅向已加载的类授予权限,以访问创建URLClassLoader时指定的URL。

Since: 1.2 由于: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): 花哨的步法可以将其扩展为支持使用通配路径名来拾取整个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;
        }
    }

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. 将.java和.class文件放在单独的文件夹中,而又依赖于jar文件中的三分之一,而无需以编程方式更改类路径,这并不稀奇。 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. 如果这样做是因为您不想每次都在命令行上键入类路径,那么建议您使用Shell脚本或批处理文件。 Better yet, an IDE. 更好的是,IDE。 The question I really have is why are you doing trying to manage the classpath in code? 我真正的问题是,为什么要尝试在代码中管理类路径?

You could implement your own class loader , but that class/jar has to be in the classpath for it to be executed. 您可以实现自己的类加载器 ,但是该类/ jar必须位于类路径中才能执行。

try 尝试

java -cp *.jar:. myClass

or 要么

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

or 要么

java -jar file.jar

You can write a batch file or shell script file to export the classpath and run the java program. 您可以编写批处理文件或Shell脚本文件以导出类路径并运行Java程序。 In Windows, 在Windows中,

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

In Unix, export classpath=%classpath%:../classes:../jars/* java ParserTester 在Unix中,导出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. 如果将文件名命名为parser.bat或parser.sh,则可以通过在相应的OS中调用parser来运行该文件。

From java 1.6, you can include all the jars in a directory into the classpath just by saying /* 从Java 1.6开始,只需说出/ *,就可以将目录中的所有jar都包含到类路径中

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. 如果尝试动态生成Java文件,请进行编译并将其添加到类路径中,请事先在类路径中设置生成类文件的目录。 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. 如果要修改已经生成的Java类,则基本上是在修改后重新编译,并且如果要加载新类,则需要使用自定义类加载器来避免对该类进行缓存。

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. 这是一种古老的设计模式(使用80年代及以前的语言),但今天仍然使用很多。 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. 许多现代的开源程序使用Shell脚本和批处理文件等来执行此操作。例如,Apache Tomcat。 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) 您可以像使用Java一样轻松地使包装器运行,并使其通过命令行exec启动软件(请确保在* NIX中的exec命令末尾添加“&”,这样包装器就可以退出而仅使软件运行)。 ..还可以让您关闭shell窗口而不必终止进程)

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 java parserTester

instead of 代替

java -classpath ../classes;../jar;. java -classpath ../classes;../jar;。 parserTester 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. 从main方法启动另一个类,然后以编程方式在其中设置类路径。
  • End of history. 历史的终结。

Something like the following "java -pseudo code " 类似于以下“ 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. 如果您想做其他事情,我会很乐意提供帮助。

Excellent good post, in my case I did this to work well (note: Windows specific): 优秀的好帖子,就我而言,我这样做很好(请注意:特定于Windows):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM