类的加载器
一.类加载器的分类:
启动类加载器(引导类加载器,Bootstrap ClassLoader):加载一些java核心类的jar包及扩展类加载器和系统类加载器
扩展类加载器(Extension ClassLoader):主要用于加载(D:\jdk1.8\jre\lib\ext,C:\WINDOWS\Sun\Java\lib\ext)
下的jar包
系统类加载器(应用程序类加载器,Application ClassLoader):父类加载器为扩展类加载器,它负责加载环境变量classpath
或系统属性java.class.path指定路径下的类库,可以通过ClassLoader.getSystemClassLoader()来获取该类的加载器
用户自定义加载器(User ClassLoader):java开发者可以自定义类加载器来实现类库的动态加载,加载源可以是本地的jar包,也可以是
网络上的远程资源
二.ClassLoader源码解析:
重要的方法:loadClass() 、 findClass() 、 defineClass() 、 preDefineClass()
1 | protected Class<?> loadClass(String name, boolean resolve) |
三.Class.forName是一个静态方法与ClassLoader.loadClass
区别:Class.forName是一个静态方法,该方法将Class加载到内存的同时,会执行类的初始化;
ClassLoader.loadClass是一个实例方法,该方法将Class文件加载到内存时,并不会执行类的初始化,直到这个类第一次使用时
才会初始化
四.双亲委派机制:
(1).定义:双亲委派机制的的具体体现为:当前ClassLoader加载类时会先检查他的父类加载器命名空间中是否加载过该类型,加载了,直接返回该类,没有加载,继续检查父类加载器,直到引导类加载器,如果父类加载器任务能够完成加载任务,则成功返回,只有父类加载器无法完成此加载任务时,才会自己去加载;
(2).为什么要使用双亲委派机制:
避免了类的重复加载,确保一个类是全局唯一性的,通过这种层级关系避免了类的重复加载;
保护程序安全,防止核心API被随意篡改(例如在src下创建java.lang包,编写自己的String类);
补充:在一个类加载器的命名空间中,同一个类型的类只会有一个;
注意:同一个类型由不同的类加载器加载,执行类型转换时会发生异常;
(3).双亲委派机制的弊端:
底层ClassLoader可以通过parent属性来获取父类的所加载的类,但是顶层ClassLoader无法访问底层ClassLoader所加载的类
五.在代码层面双亲委派机制是如何体现的:
主要体现在loadClass方法中,会先检查当前ClassLoader命名空间中是否加载过该类型,加载过,直接返回,否则会调用
当前ClassLoader的parent也就是父加载器的loadClass方法,直到parent为null,会去检查引导类加载器是否加载过该类型,如果父类加载器任务能够完成加载任务,则成功返回,只有父类加载器无法完成此加载任务时,才会自己去加载;
六.双亲委派机制对java核心类库的保护:
在findClass方法中会调用defineClass方法,该方法中会调用defineClass方法,最终会调用preDefineClass方法,该方法会对加载类进行检查,对java核心类库的保护
七.破坏双亲委派机制的行为有哪些:
(1).第一次双亲委派机制的破坏:自定义类加载器重写loadClass方法破坏双亲委派机制,解决建议:不推荐重写loadClass方法,
建议重写findClass方法,保证双亲委派机制;
(2).第二次双亲委派机制的破坏:顶层ClassLoader加载的基础类(如JNDI),无法加载第三方提供的一些代码实现,解决方法:
使用线程上下文加载器,通过Launcher类将线程的上下文加载器设置为系统类加载器,再通过系统类加载器去加载第三方代码实现;
(3).第三次双亲委派机制的破坏:代码的热替换,模块的热部署
八.线程上下文类加载器:
Launcher() —> Thread.currentThread().setContextClassLoader(this.loader);
1 | public Launcher() { |
九.沙箱安全机制:
保证程序安全
保护Java原生的JDK代码
十.Java9新特性关于双亲委派机制的改变:
(1).扩展类加载器(Extension ClassLoader)变成了PlatformClassLoader(平台类加载器);
(2).可以通过ClassLoader.getPlatformClassLoader()获取平台类加载器;
(3).删除了URLClassLoader;
(4).引导类加载更名为BootClassLoader并集成进java API;
-XX:+TraceClassLoading:打印当前加载的类