::我的理解
类加载器,主要是类在加载阶段,将class文件加载到JVM内存的过程,最终会在内存中生成一个代表这个类的java.lang.Class对象。
那存在的意义呢?能想到的有几点,不一定对。
- 为了对class的处理方式,如class来源于网络、class加密等
- 为了对加载的路径优先级问题,比如同一个类,在系统也有,用户目录也有,怎么处理?这就涉及到了类加载器的双亲委派机制
分类
- 启动类加载器(引导类加载器,Bootstrap ClassLoader)
- 这个类加载使用C/C++ 语言实现,嵌套在JVM 内部
- 它用来加载Java的核心库(
JAVA_HOME/jre/lib/rt.jar
、resource.jar
或sun.boot.class.path
路径下的内容),用于提供JVM自身需要的类 - 并不继承自
java.lang.ClassLoader
,没有父加载器 - 加载扩展类和应用程序类加载器,并指定为他们的父类加载器
- 出于安全考虑,Boostrap 启动类加载器只加载名为java、Javax、sun等开头的类
- 扩展类加载器(Extension ClassLoader)
- java语言编写,由
sun.misc.Launcher$ExtClassLoader
实现 - 派生于 ClassLoader
- 父类加载器为启动类加载器
- 从
java.ext.dirs
系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext
子目录(扩展目录)下加载类库。如果用户创建的JAR 放在此目录下,也会自动由扩展类加载器加载
- 应用程序类加载器(也叫系统类加载器,AppClassLoader)
- java语言编写,由
sun.misc.Lanucher$AppClassLoader
实现 - 派生于 ClassLoader
- 父类加载器为扩展类加载器
- 它负责加载环境变量
classpath
或系统属性java.class.path
指定路径下的类库 - 该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载的
- 通过
ClassLoader#getSystemClassLoader()
方法可以获取到该类加载器
- 自定义类加载器
4.1 为什么要自定义类加载器?- 隔离加载类
- 修改类加载的方式
- 扩展加载源(可以从数据库、云端等指定来源加载类)
- 防止源码泄露(Java代码容易被反编译,如果加密后,自定义加载器加载类的时候就可以先解密,再加载)
4.2 用户自定义加载器实现步骤 - 开发人员可以通过继承抽象类
java.lang.ClassLoader
类的方式,实现自己的类加载器,以满足一些特殊的需求 - 在JDK1.2之前,在自定义类加载器时,总会去继承ClassLoader类并重写loadClass()方法,从而实现自定义的类加载类,但是JDK1.2之后已经不建议用户去覆盖loadClass()方式,而是建议把自定义的类加载逻辑写在findClass()方法中
- 编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URLClassLoader类,这样就可以避免自己去编写findClass()方法及其获取字节码流的方式,使自定义类加载器编写更加简洁
4.3 如何自定义类加载器 - 需要保留双亲委派模型:
extends ClassLoader
,重写findClass()
- 破坏双亲委派模型:直接重写
loadClass()
代码热替换