如何从classloader获取classpath?
我正在使用一些第三方代码,当给定一个'-classpath'命令行参数没有设置java.class.path,而只是创build一个类加载器,将命令行上指定类path的项目的所有URL添加到类加载器,然后将其设置为上下文类加载器。 在我编写的这段代码的插件类中,我得到了这个类加载器的一个实例,不知何故需要用它来取回底层的类path,以便我可以在调用JavaCompiler.getTask(…)中使用它。 )并编译一些其他的代码。 然而似乎没有办法从ClassLoader中获取ClassPath,因为java.class.path未被设置,我似乎无法访问应用程序最初被调用的基础类path…任何想法?
如果类加载器使用URL,则它必须是URLClassloader
。 您可以访问的是与其父ClassLoader
一起定义类path的URL。
要获取url,只需执行以下操作:
((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
其他答案在大多数情况下都是正确的,但是在一些设置中比较复杂:例如, Maven , Tomcat和JUnit都有自己的类path支持,并且不使用系统类path。
到目前为止,这是我设法得到的最完整的系统(这个代码来自我的Fast Classpath Scanner项目):
/** 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; }
为了将来的参考,如果您需要将类path传递给ProcessBuilder
:
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.abcTestProgram");
如果其他答案不起作用,请尝试以下操作:
ClassLoader cl = ClassLoader.getSystemClassLoader(); URL[] urls = ((URLClassLoader) cl).getURLs(); for (URL url: urls) { System.out.println(url.getFile()); }
将这段代码放到一个空的jsp页面中,以查看每个级别加载的classLoader层次结构和关联的jar。
下面的visit()方法也可以单独使用
<%! 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>