簡體   English   中英

是否可以在Java中動態“添加”到類路徑?

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

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

如何以編程方式獲取上述命令中的功能? 像,可以運行為:

java parserTester

並得到相同的結果? 我嘗試使用URLClassLoader,但它修改了類路徑,並且沒有添加到它。

謝謝!


感謝Milhous的回復。 但這就是我要嘗試的方法。如何將罐子首先放入類路徑? 我也嘗試使用自定義類加載器:(

那行得通。。但是很抱歉,我只需要以以下方式運行它:java parserTester我想知道這樣的事情是否可能???

需要這樣,因為我在單獨的文件夾中有parserTester.java和.class。 我需要保留文件結構。 parserTester在單獨的jar文件夾中使用jar。

您可以使用java.net.URLClassLoader來加載具有您希望的任何URL的程序定義列表的類:

公共類URLClassLoader擴展了SecureClassLoader

該類加載器用於從同時引用JAR文件和目錄的URL的搜索路徑中加載類和資源。 假定任何以“ /”結尾的URL均指向目錄。 否則,假定該URL引用將根據需要打開的JAR文件。

隨后加載類和資源時,將使用創建URLClassLoader實例的線程的AccessControlContext。

默認情況下,僅向已加載的類授予權限,以訪問創建URLClassLoader時指定的URL。

由於: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;
        }
    }

我必須同意其他兩個海報,聽起來您正在使測試課程過於復雜。 將.java和.class文件放在單獨的文件夾中,而又依賴於jar文件中的三分之一,而無需以編程方式更改類路徑,這並不稀奇。 如果這樣做是因為您不想每次都在命令行上鍵入類路徑,那么建議您使用Shell腳本或批處理文件。 更好的是,IDE。 我真正的問題是,為什么要嘗試在代碼中管理類路徑?

您可以實現自己的類加載器 ,但是該類/ jar必須位於類路徑中才能執行。

嘗試

java -cp *.jar:. myClass

要么

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

要么

java -jar file.jar

您可以編寫批處理文件或Shell腳本文件以導出類路徑並運行Java程序。 在Windows中,

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

在Unix中,導出classpath =%classpath%:../ classes:../ jars / * java ParserTester

如果將文件名命名為parser.bat或parser.sh,則可以通過在相應的OS中調用parser來運行該文件。

從Java 1.6開始,只需說出/ *,就可以將目錄中的所有jar都包含到類路徑中

如果嘗試動態生成Java文件,請進行編譯並將其添加到類路徑中,請事先在類路徑中設置生成類文件的目錄。 它應該加載該類。 如果要修改已經生成的Java類,則基本上是在修改后重新編譯,並且如果要加載新類,則需要使用自定義類加載器來避免對該類進行緩存。

我認為您想要的是“執行包裝”或特定於平台的“啟動器” ...通常,此組件用於檢測操作系統,體系結構和依賴項,然后在啟動應用程序之前進行調整。 這是一種古老的設計模式(使用80年代及以前的語言),但今天仍然使用很多。 想法是您的程序可以與系統和環境無關,並且啟動程序將進行准備並將所需的一切告知軟件。 許多現代的開源程序使用Shell腳本和批處理文件等來執行此操作。例如,Apache Tomcat。 您可以像使用Java一樣輕松地使包裝器運行,並使其通過命令行exec啟動軟件(請確保在* NIX中的exec命令末尾添加“&”,這樣包裝器就可以退出而僅使軟件運行)。 ..還可以讓您關閉shell窗口而不必終止進程)

我明白嗎?! 您擁有啟動類而不指定類路徑並在運行時加載它的唯一原因是? ...

java parserTester

代替

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

可能我沒弄明白你的理由。 但是,如果您想要的是“那”,則可以執行以下操作(盡管對我而言意義不大)

  • 上課
  • 從main方法啟動另一個類,然后以編程方式在其中設置類路徑。
  • 歷史的終結。

類似於以下“ java -pseudo code”

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

請告訴我我是否正確。 如果您想做其他事情,我會很樂意提供幫助。

優秀的好帖子,就我而言,我這樣做很好(請注意:特定於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