• java.lang.ClassLoader 抽象类,根据类名称,找到类的字节码,加载类,生成Class对象,获取类资源如配置文件
  • 引导加载类(bootstrap class loader)

用来加载java的核心类库的,使用原生代码来实现的(c++),并不继承自java.lang.ClassLoader

  • 扩展类加载库(extension class loader)

用来java的扩展库,由sunmisc.Launcher$ExtClassLoader实现,java实现,继承自java.lang.ClassLoader

  • 应用程序类加载器(application class loader)

根据java应用的类路径(classpath,java.class.path)加载类,由sunmisc.Launcher$AppClassLoader实现,java实现,继承自java.lang.ClassLoader

  • 自定义类加载器

通过继承java.lang.ClassLoader实现自己的类加载器 java实现

 

他们之间的关系是树形结构,但不是继承关系,而是组合使用关系

flanJava扩展包下载 java扩展库_加载

public class Demo02 {

public static void main(String[] args) {

System.out.println(ClassLoader.getSystemClassLoader());//当前使用的类加载器

System.out.println(ClassLoader.getSystemClassLoader().getParent());

//父亲类加载器,这个父亲指的是属性结构的父亲,不知继承关系

System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
System.out.println(System.getProperty("java.class.path"));//当前类加载path的路径

}

输出

flanJava扩展包下载 java扩展库_flanJava扩展包下载_02

第三行是boostrap class loader,c++实现的所以java中无法访问

}

 

类加载器的代理模式

 

双亲委托机制(代理模式的一种)

       某个特定的类加载器在接到加载类的请求时,将任务委托给父类(树结构的父类)加载器,直到根节点的类加载器,如果该加载器无法加载类,再一层一层向下加载,直到加载成功,就返回。保证了Java核心库的类型安全,类加载器除了用于加载类,也是最安全的保障。比如java.lang.String类是java的核心类库,你要加载一个String类,采用双亲委托机制就会确保你加载到java核心类库的String类,而不是会有人自己定义的路径为java.lang.String类。

      但是并不是所有的类加载器都是用双亲代理模式机制,Tomcat服务器类加载器也是用代理模式,只是不是双亲委托机制,而是自己先去加载,加载不了,再给父类。

线程上下文类加载器

抛弃双亲委托机制,每一个线程都有一个关联的上下文类加载器,默认是系统类加载器,可以用下面第二个方法进行更改,比如更改为自定义的类加载器。

Thread.currentThread().getContextClassLoader();

Thread.currentThread().setContextClassLoader();

自定义类加载器

 

双亲委派纸质是在loadclass()方法实现的,每次都会让parent来加载类就是调用parent类加载器的findclass()方法

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

不打破双亲委派机制

那么在自己定义类加载器就是继承ClassLoader,重写findClass方法,不打破双亲委派机制,当父类加载类都加载不到这个类,就使用自己类重写的findclass方法,实现自己的功能

打破双亲委派机制

如果要打破双亲委派机制,不仅要重写findClass方法还有重写loadclass方法