UrlClassLoader详解

2,381 阅读2分钟

Java中有四类加载器。

  1. BootStrap ClassLoader:启动类加载器,加载\lib目录下的符合特定名字的jar包
  2. Extention ClassLoader: 扩展类加载器,加载\lib\ext目录下扩展的jar包
  3. Application ClassLoader:应用程序类加载器,加载指定的classpath下面的jar包
  4. Custom ClassLoader:自定义的类加载器

而加载Class类的顺序是有优先级的,这就是类加载器的双亲委派机制

双亲委派机制的工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。

image.png

一般在加载器的构造函数中可以指定父加载器

protected ClassLoader(ClassLoader parent)

没指定则默认父加载器为AppClassLoader ,指定为null父加载器则为BootstrapClassLoader。

而本文要介绍的urlclassloader是继承自classloader

urlclassloader可以指定一串路径,然后在路径下面寻找要加载的类。这个类加载器如果没有指定的话父类加载器也是AppClassLoader

举例:我们将HelloWorld.class文件放于:N:/

public class HelloWorld {
    public HelloWorld(){
        System.out.println("Hello World");
    }
}

通过urlclassloader去加载这个类

public class UrlclassloaderTest {
    @Test
    public void urlclassloader() throws Exception{
        File file = new File("N:/");
        URL url = file.toURI().toURL();
        ClassLoader loader = new URLClassLoader(new URL[]{url});
        Class<?> clazz = loader.loadClass("HelloWorld");
        System.out.println("当前加载器"+clazz.getClassLoader());
        System.out.println("父类加载器"+clazz.getClassLoader().getParent());
        clazz.newInstance();
    }
}

在构造方法中没有指定父类加载器,所以默认为AppClassLoader

image.png

如果在当前的classpath也放置一个Hello.class文件,那么就会被APPClassLoader加载,而且加载不到N盘的那个文件

public class HelloWorld {
    public HelloWorld(){
        System.out.println("this is annother Hello World");
    }
}

image.png

如果把URLClassLoader的父类加载器设置为BootStrap加载器,就可以避免AppClassLoader加载classpath下的同名文件。

public URLClassLoader(URL[] urls, ClassLoader parent) 

只需要将parent设为null,这样父加载器就是BootStrap加载器

image.png