Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 9,与ClassLoader.getSystemClassLoader的兼容性问题_Java_Classloader_Java 9_Urlclassloader - Fatal编程技术网

Java 9,与ClassLoader.getSystemClassLoader的兼容性问题

Java 9,与ClassLoader.getSystemClassLoader的兼容性问题,java,classloader,java-9,urlclassloader,Java,Classloader,Java 9,Urlclassloader,下面的代码将jar文件添加到构建路径中,它在Java8中运行良好。但是,它在Java9中抛出异常,该异常与转换到URLClassLoader有关。有没有办法解决这个问题?一个最佳的解决方案将对其进行编辑,使其与Java8和Java9一起工作 private static int AddtoBuildPath(File f) { try { URI u = f.toURI(); URLClassLoader urlClassLoader = (URLClas

下面的代码将jar文件添加到构建路径中,它在Java8中运行良好。但是,它在Java9中抛出异常,该异常与转换到URLClassLoader有关。有没有办法解决这个问题?一个最佳的解决方案将对其进行编辑,使其与Java8和Java9一起工作

private static int AddtoBuildPath(File f) {
    try {
        URI u = f.toURI();
        URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Class<URLClassLoader> urlClass = URLClassLoader.class;
        Method method = urlClass.getDeclaredMethod("addURL", URL.class);
        method.setAccessible(true);
        method.invoke(urlClassLoader, u.toURL());
    } catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | MalformedURLException | IllegalAccessException ex) {
        return 1;
    }

    return 0;
}
private static int AddtoBuildPath(文件f){
试一试{
uriu=f.toURI();
URLClassLoader URLClassLoader=(URLClassLoader)ClassLoader.getSystemClassLoader();
类urlClass=URLClassLoader.Class;
方法Method=urlClass.getDeclaredMethod(“addURL”,URL.class);
方法setAccessible(true);
调用(urlClassLoader,u.toURL());
}catch(NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | MalformedURLException | IllegalAccessException ex){
返回1;
}
返回0;
}

您遇到了这样一个事实。正如
ClassLoader::getSystemClassLoader
的返回类型所示,这是一个实现细节,尽管有大量代码依赖它

根据注释判断,您正在寻找一种在运行时动态加载类的方法。在Java9中,这不能通过附加到类路径来完成

<>你应该考虑为此创建一个新的类加载器。这还有一个额外的优点,即您可以去掉新类,因为它们没有加载到应用程序类装入器中。如果您是针对Java 9进行编译,您应该仔细阅读-它们为您提供了加载全新模块图的清晰抽象。

指向。答案是正确的:

Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));
这里提到的注意事项也很重要:

注意事项:

java.util.ServiceLoader使用线程的ClassLoader上下文thread.currentThread().setContextClassLoader(specialloader)

DriverManager并不尊重调用类的“ClassLoader”,而不是线程的ClassLoader。直接使用Class.forName(“drivername”,true,新的URLClassLoader(urlarrayofextrajarsordirs).newInstance()创建驱动程序

激活使用线程的类加载器上下文(对javax.mail很重要)


不久前,我在这个问题上遇到了一些问题,很多人都使用了与问题中类似的方法

private static int AddtoBuildPath(File f)
在运行时将路径动态添加到类路径。问题中的代码在多个方面可能是错误的样式:1)假设
ClassLoader.getSystemClassLoader()
返回一个
URLClassLoader
是一个未记录的实现细节,2)使用反射将
addURL
公开可能是另一个

动态添加类路径的更简洁的方法

如果您需要通过“class.forName”使用额外的类路径URL进行类加载,那么一个干净、优雅且兼容(Java 8到10)的解决方案如下:

object ClassloaderHelper {
  def getURLs(classloader: ClassLoader) = {
    // jdk9+ need to use reflection
    val clazz = classloader.getClass

    val field = clazz.getDeclaredField("ucp")
    field.setAccessible(true)
    val value = field.get(classloader)

    value.asInstanceOf[URLClassPath].getURLs
  }
}

val classpath =
  (
    // jdk8
    // ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs ++
    // getClass.getClassLoader.asInstanceOf[URLClassLoader].getURLs

    // jdk9+
    ClassloaderHelper.getURLs(ClassLoader.getSystemClassLoader) ++
    ClassloaderHelper.getURLs(getClass.getClassLoader)
  )
1) 通过扩展URL类加载器编写自己的类加载器,使用公共
addURL
方法

public class MyClassloader extends URLClassLoader {

    public MyClassloader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public void addURL(URL url) {
        super.addURL(url);
    }
}
2) 声明类加载器的(单例/应用程序范围)对象

private final MyClassloader classLoader;
并通过

classLoader = new MyClassloader(new URL[0], this.getClass().getClassLoader());
注意:系统类加载器是父类。通过
classLoader
加载的类知道哪些类可以通过
this.getClass().getClassLoader()
加载,但不能反过来加载

3) 在需要时添加其他类路径(动态):

4) 通过singleton类加载器实例化对象或应用程序

cls = Class.forName(name, true, classLoader);
注意:由于类加载器尝试在加载类之前委托给父类加载器(以及将父类委托给其父类),您必须确保要加载的类对父类加载器不可见,以确保它是通过给定的类加载器加载的。为了更清楚地说明这一点:如果您在系统类路径上有
ClassPathB
,然后将
ClassPathB
和一些
ClassPathA
添加到您的自定义
类加载器中,t如果
ClassPathB
下的类将通过系统类加载器加载,而
ClassPathA
下的类对它们来说是未知的。但是,如果从系统类路径中删除
ClassPathB
,则这些类将通过自定义
classloader
加载,然后用户将知道ClassPathA下的类B类的

5)您可以考虑通过< /P>将类加载程序传递给线程。

setContextClassLoader(classLoader)

如果线程使用
getContextClassLoader

,如果您只是想读取当前类路径,例如,因为您想使用与当前类路径相同的类路径启动另一个JVM,则可以执行以下操作:

object ClassloaderHelper {
  def getURLs(classloader: ClassLoader) = {
    // jdk9+ need to use reflection
    val clazz = classloader.getClass

    val field = clazz.getDeclaredField("ucp")
    field.setAccessible(true)
    val value = field.get(classloader)

    value.asInstanceOf[URLClassPath].getURLs
  }
}

val classpath =
  (
    // jdk8
    // ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs ++
    // getClass.getClassLoader.asInstanceOf[URLClassLoader].getURLs

    // jdk9+
    ClassloaderHelper.getURLs(ClassLoader.getSystemClassLoader) ++
    ClassloaderHelper.getURLs(getClass.getClassLoader)
  )
默认情况下,$AppClassLoader类中的最终字段不能通过反射访问,需要向JVM传递一个额外的标志:

--add-opens java.base/jdk.internal.loader=ALL-UNNAMED

我找到了这个,为我工作

字符串pathSeparator=Syste.getProperty(“path.separator”); 字符串[]classPathEntries=System.getProperty(“java.class.path”).split(路径分隔符)


从网站上我得到了一个运行在Java 8中的spring boot应用程序。我的任务是将它升级到Java 11版本

面临的问题:

import java.net.URL;

/**
 * This class has been created to make the code compatible after migration to Java 11
 * From the JDK 9 release notes: "The application class loader is no longer an instance of
 * java.net.URLClassLoader (an implementation detail that was never specified in previous releases).
 * Code that assumes that ClassLoader.getSytemClassLoader() returns a URLClassLoader object will
 * need to be updated. Note that Java SE and the JDK do not provide an API for applications or
 * libraries to dynamically augment the class path at run-time."
 */

public class ClassLoaderConfig {

    private final MockClassLoader classLoader;

    ClassLoaderConfig() {
        this.classLoader = new MockClassLoader(new URL[0], this.getClass().getClassLoader());
    }

    public MockClassLoader getClassLoader() {
        return this.classLoader;
    }
}
import java.net.URL;
import java.net.URLClassLoader;

public class MockClassLoader extends URLClassLoader {

    public MockClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public void addURL(URL url) {
        super.addURL(url);
    }
}
原因:java.lang.ClassCastException:jdk.internal.loader.ClassLoaders$AppClassLoader(在模块:java.base中)无法转换为java.net.URLClassLoader(在模块:java.base中)

使用的方法:

import java.net.URL;

/**
 * This class has been created to make the code compatible after migration to Java 11
 * From the JDK 9 release notes: "The application class loader is no longer an instance of
 * java.net.URLClassLoader (an implementation detail that was never specified in previous releases).
 * Code that assumes that ClassLoader.getSytemClassLoader() returns a URLClassLoader object will
 * need to be updated. Note that Java SE and the JDK do not provide an API for applications or
 * libraries to dynamically augment the class path at run-time."
 */

public class ClassLoaderConfig {

    private final MockClassLoader classLoader;

    ClassLoaderConfig() {
        this.classLoader = new MockClassLoader(new URL[0], this.getClass().getClassLoader());
    }

    public MockClassLoader getClassLoader() {
        return this.classLoader;
    }
}
import java.net.URL;
import java.net.URLClassLoader;

public class MockClassLoader extends URLClassLoader {

    public MockClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public void addURL(URL url) {
        super.addURL(url);
    }
}
创建一个类:

import java.net.URL;

/**
 * This class has been created to make the code compatible after migration to Java 11
 * From the JDK 9 release notes: "The application class loader is no longer an instance of
 * java.net.URLClassLoader (an implementation detail that was never specified in previous releases).
 * Code that assumes that ClassLoader.getSytemClassLoader() returns a URLClassLoader object will
 * need to be updated. Note that Java SE and the JDK do not provide an API for applications or
 * libraries to dynamically augment the class path at run-time."
 */

public class ClassLoaderConfig {

    private final MockClassLoader classLoader;

    ClassLoaderConfig() {
        this.classLoader = new MockClassLoader(new URL[0], this.getClass().getClassLoader());
    }

    public MockClassLoader getClassLoader() {
        return this.classLoader;
    }
}
import java.net.URL;
import java.net.URLClassLoader;

public class MockClassLoader extends URLClassLoader {

    public MockClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public void addURL(URL url) {
        super.addURL(url);
    }
}
创建另一个类:

import java.net.URL;

/**
 * This class has been created to make the code compatible after migration to Java 11
 * From the JDK 9 release notes: "The application class loader is no longer an instance of
 * java.net.URLClassLoader (an implementation detail that was never specified in previous releases).
 * Code that assumes that ClassLoader.getSytemClassLoader() returns a URLClassLoader object will
 * need to be updated. Note that Java SE and the JDK do not provide an API for applications or
 * libraries to dynamically augment the class path at run-time."
 */

public class ClassLoaderConfig {

    private final MockClassLoader classLoader;

    ClassLoaderConfig() {
        this.classLoader = new MockClassLoader(new URL[0], this.getClass().getClassLoader());
    }

    public MockClassLoader getClassLoader() {
        return this.classLoader;
    }
}
import java.net.URL;
import java.net.URLClassLoader;

public class MockClassLoader extends URLClassLoader {

    public MockClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public void addURL(URL url) {
        super.addURL(url);
    }
}
现在在主类的当前线程中设置它(就在应用程序的开头)


希望此解决方案适用于您的!!!

参考Edi的解决方案,此解决方案适用于我:

public final class IndependentClassLoader extends URLClassLoader {

    private static final ClassLoader INSTANCE = new IndependentClassLoader();

    /**
     * @return instance
     */
    public static ClassLoader getInstance() {

        return INSTANCE;
    }

    private IndependentClassLoader() {

        super(getAppClassLoaderUrls(), null);
    }

    private static URL[] getAppClassLoaderUrls() {

        return getURLs(IndependentClassLoader.class.getClassLoader());
    }

    private static URL[] getURLs(ClassLoader classLoader) {

        Class<?> clazz = classLoader.getClass();

        try {
            Field field = null;
            field = clazz.getDeclaredField("ucp");
            field.setAccessible(true);

            Object urlClassPath = field.get(classLoader);

            Method method = urlClassPath.getClass().getDeclaredMethod("getURLs", new Class[] {});
            method.setAccessible(true);
            URL[] urls = (URL[]) method.invoke(urlClassPath, new Object[] {});

            return urls;

        } catch (Exception e) {
            throw new NestableRuntimeException(e);
        }

    }
}
公共最终类独立类加载器扩展URLClassLoader{
私有静态最终类加载器实例=新独立类加载器();
/**
*@return实例
*/
公共静态类装入