且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-09-19 17:07:10

我偶然发现了这个问题不久前。很多,我使用了类似于问题的方法

I have stumbled over this issue a while ago. As many, I had used a method similar to that in the question

private static int AddtoBuildPath(File f)

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

to dynamically add paths to the classpath at runtime. The code in the question is probably bad style in multiple aspects: 1) assuming that ClassLoader.getSystemClassLoader() returns an URLClassLoader is an undocumented implementation detail and 2) using reflection to make addURL public is maybe another one.

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

如果您需要为类使用其他类路径URL通过 Class.forName 加载,一个干净,优雅和兼容(Java 8到10)的解决方案如下:

In case that you need to use the additional classpath URLs for class loading though „Class.forName", a clean, elegant and compatible (Java 8 to 10) solution is the following:

1)通过扩展URL类加载器编写自己的类加载器,具有公共addURL方法

1) Write your own class loader by extending URL classloader, having a public addURL methods

public class MyClassloader extends URLClassLoader {

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

    public void addURL(URL url) {
        super.addURL(url);
    }
}

2)声明一个(单例/ app宽)对象您的类加载器

2) Declare a (singleton/app wide) object of your classloader

private final MyClassloader classLoader;

并通过

classLoader = new MyClassloader(new URL[0], this.getClass().getClassLoader());

注意:系统类加载器是父级。通过 classLoader 加载的类知道那些可以通过 this.getClass()。getClassLoader()加载但不能加载的其他类两种方式。

Note: The system class loader is the parent. Classes loaded though classLoader know those who can be loaded through this.getClass().getClassLoader() but not the other way around.

3)在需要时(动态)添加额外的类路径:

3) Add additional classpaths whenever needed (dynamically):

File file = new File(path);
if(file.exists()) {
    URL url = file.toURI().toURL();
    classLoader.addURL(url);
}

4)通过单件类加载器实现对象或您的应用程序

4) Instanciate objects or your app though your singleton classloader via

cls = Class.forName(name, true, classLoader);

注意:由于类加载器在加载类(和父类)之前尝试委托给父类加载器在父类中,你必须确保要加载的类对父类加载器不可见,以确保通过给定的类加载器加载。

Note: Since class loaders try a delegation to the parent class loader prior loading a class (and the parent to its parent), you have to make sure that the class to load is not visible to the parent class loader to make sure that is loaded through the given class loader.

5)您可以考虑通过

setContextClassLoader(classLoader)

如果线程使用 getContextClassLoader