web-gelistirme-sc.com

Sınıf yükleyiciden classpath nasıl elde edilir?

Bir '-classpath' komut satırı argümanı Java.class.path ayarını ayarlamayan ancak bunun yerine sadece bir sınıf yükleyici oluşturduğunda bazı üçüncü taraf kodları kullanıyorum, ancak bunun yerine sadece bir sınıf yükleyici oluşturduğumda, sınıf yoluna belirtilen sınıf yolundaki komut satırındaki öğelerin tüm url'lerini ekliyor ve sonra onu bağlam sınıfı yükleyici olarak ayarlar .. Yazdığım bu koda bir eklenti sınıfında, bu sınıf yükleyicinin bir örneğini alıyorum ve bir şekilde bunu temeldeki sınıf yolunu geri almak için kullanmam gerekiyor. JavaCompiler.getTask (...) 'in çağrısında kullanabilir ve anında diğer bazı kodları derleyebilir .Ancak ClassPath'i ClassLoader'dan ve Java.class olarak almak için zaten görünmüyor. yol ayarlanmadı, uygulamanın başlangıçta çağrıldığı temeldeki sınıf yoluna erişemiyorum ... Herhangi bir fikir?

45

Sınıf yükleyici URL kullanıyorsa, URLClassloader olmalıdır. Erişiminiz olan, classpath 'ı bunun için üst ClassLoader ile birlikte tanımlayan URL'ler.

URL’leri almak için aşağıdakileri yapmanız yeterlidir:

((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
54
Adel Boutros

GÜNCELLEME: Aşağıdaki orijinal cevabım oldukça yetersiz, şu anda FastClasspathScanner'ı geliştirmek için üç yıl harcadım ve bu kitaplıkla çalışmayan belirli sınıf yolu ortamları hakkında çok sayıda hata raporu aldım. FastClasspathScanner şimdi çok sayıda karmaşık sınıf yolu belirtme mekanizmasını yönetiyor . Sadece sınıf yolunu bulmak bile genel durumda delicesine karmaşık olabilir (onu taramaya bile gerek kalmadan), çünkü sınıf yoluna kavanoz ve dizin eklemenin çok fazla yolu vardır.

Birincisi, aşağıda verdiğim kod sadece URLClassLoader kodunu kullanır ve çoğu ana çalışma ortamı ve konteyner bunu uzatmaz, kendi sınıf yükleyicilerini sıfırdan uygularlar. Ancak, Java 9+ durumunda bundan çok daha karmaşık hale gelir, çünkü geleneksel sınıf yolu hala var olmasına rağmen, gelecekte her şey sınıf yolunu değil, modül yolunu kullanmaya doğru ilerleyecektir. Modüllerin URL'leri vardır, ancak bunlar "jrt:/" URL'leridir, "file:/" URL'leri değildir ve modül URL'leri aslında bir dosya yolu içermez, yalnızca modül adını içerir; bu nedenle genel olarak bile bu diskteki modülü bulamazsınız. Tek seçeneğiniz, (çok kapsüllenmiş) modül sistemini modüllerle çalışmak için kullanmaktır. Buradaki modül yolunun nasıl taranacağını yazdım .

FastClasspathScanner sayısız karmaşık sınıf yolu özellik mekanizmasını yönetir, bu nedenle tekerleği yeniden icat etmeniz gerekmez. FastClasspathScanner'dan classpath girişlerinin bir listesini alabilirsiniz - bu, vahşi ortamda bulacağınız tüm çeşitli classpath özellik mekanizmalarıyla çalışan bir şey elde etme zorunluluğunu ortadan kaldırır. (Son bağlantı koparsa özür dilerim - FCS için API ve dokümanlar yakında değişecek.)

-

[Eski cevap - eski:]

Diğer cevaplar çoğu durumda doğrudur, ancak bazı ayarlarda olduğundan daha karmaşık hale gelir: örn. Maven , Tomcat ve JUnit'in kendi sınıf yolu desteği vardır ve sistem sınıf yolunu kullanmazlar.

Şimdiye kadar bu, şu ana kadar bulabildiğim en eksiksiz sistemdi (bu kod benim Hızlı Sınıf Yolu Tarayıcım projemden):

/** The unique elements of the classpath, as an ordered list. */
private final ArrayList<File> classpathElements = new ArrayList<>();

/** The unique elements of the classpath, as a set. */
private final HashSet<String> classpathElementsSet = new HashSet<>();

/** Clear the classpath. */
private void clearClasspath() {
    classpathElements.clear();
    classpathElementsSet.clear();
}

/** Add a classpath element. */
private void addClasspathElement(String pathElement) {
    if (classpathElementsSet.add(pathElement)) {
        final File file = new File(pathElement);
        if (file.exists()) {
            classpathElements.add(file);
        }
    }
}

/** Parse the system classpath. */
private void parseSystemClasspath() {
    // Look for all unique classloaders.
    // Keep them in an order that (hopefully) reflects the order in which class resolution occurs.
    ArrayList<ClassLoader> classLoaders = new ArrayList<>();
    HashSet<ClassLoader> classLoadersSet = new HashSet<>();
    classLoadersSet.add(ClassLoader.getSystemClassLoader());
    classLoaders.add(ClassLoader.getSystemClassLoader());
    if (classLoadersSet.add(Thread.currentThread().getContextClassLoader())) {
        classLoaders.add(Thread.currentThread().getContextClassLoader());
    }
    // Dirty method for looking for any other classloaders on the call stack
    try {
        // Generate stacktrace
        throw new Exception();
    } catch (Exception e) {
        StackTraceElement[] stacktrace = e.getStackTrace();
        for (StackTraceElement elt : stacktrace) {
            try {
                ClassLoader cl = Class.forName(elt.getClassName()).getClassLoader();
                if (classLoadersSet.add(cl)) {
                    classLoaders.add(cl);
                }
            } catch (ClassNotFoundException e1) {
            }
        }
    }

    // Get file paths for URLs of each classloader.
    clearClasspath();
    for (ClassLoader cl : classLoaders) {
        if (cl != null) {
            for (URL url : ((URLClassLoader) cl).getURLs()) {
                if ("file".equals(url.getProtocol())) {
                    addClasspathElement(url.getFile());
                }
            }
        }
    }
}

/** Override the system classpath with a custom classpath to search. */
public FastClasspathScanner overrideClasspath(String classpath) {
    clearClasspath();
    for (String pathElement : classpath.split(File.pathSeparator)) {
        addClasspathElement(pathElement);
    }
    return this;
}

/**
 * Get a list of unique elements on the classpath (directories and files) as File objects, preserving order.
 * Classpath elements that do not exist are not included in the list.
 */
public ArrayList<File> getUniqueClasspathElements() {
    return classpathElements;
}
15
Luke Hutchison

İleride başvurmak üzere, sınıf yolundan ProcessBuilder dizinine geçmeniz gerekmesi durumunda:

StringBuffer buffer = new StringBuffer();
for (URL url :
    ((URLClassLoader) (Thread.currentThread()
        .getContextClassLoader())).getURLs()) {
  buffer.append(new File(url.getPath()));
  buffer.append(System.getProperty("path.separator"));
}
String classpath = buffer.toString();
int toIndex = classpath
    .lastIndexOf(System.getProperty("path.separator"));
classpath = classpath.substring(0, toIndex);
ProcessBuilder builder = new ProcessBuilder("Java",
    "-classpath", classpath, "com.a.b.c.TestProgram");
7

Diğer cevapların işe yaramadığı durumlarda şunu deneyin:

ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url: urls) {
    System.out.println(url.getFile());
}
5
Yavin5

ClassLoader hiyerarşisini ve her seviyede yüklü ilişkili kavanozları görüntülemek için bu kodu boş bir jsp sayfasına bırakın.

aşağıdaki visit () yöntemi kendi başına da kullanılabilir 

<%!
    public void visit(StringBuilder sb, int indent, ClassLoader classLoader) {
        if (indent > 20 || classLoader == null)
            return;
        String indentStr = new String(new char[indent]).replace("\0", "    ");
        sb.append("\n");
        sb.append(indentStr);
        sb.append(classLoader.getClass().getName());
        sb.append(":");
        if (classLoader instanceof Java.net.URLClassLoader) {
            Java.net.URL[] urls = ((Java.net.URLClassLoader)classLoader).getURLs();
            for (Java.net.URL url : urls) {
                sb.append("\n");
                sb.append(indentStr);
                sb.append(url);
            }
        }
        sb.append("\n");
        visit(sb, indent + 1, classLoader.getParent());
    }

%>

<%
StringBuilder sb = new StringBuilder();
visit(sb,1,this.getClass().getClassLoader());
%>
<pre>
<%=sb%>
</pre>
0
Prashant Bhate