一、类加载器
以JDK8为例:
①启动类加载器
②扩展类加载器
③应用程序类加载器
④自定义类加载器
①类加载器具有层级关系,当加载一个类的时候,要看所有的上级有没有加载此类。【双亲委派模式】
②类加载器负责在运行时将Java类动态加载到JVM(Java虚拟机),是JRE(Java运行时环境)的一部分。由于类加载器的存在,JVM无需了解底层文件或文件系统即可运行Java程序。
1.启动类加载器:Bootstrap ClassLoader
①启动类加载器是使用C++实现的,嵌套在JVM内部,因此java程序无法直接访问。getClassLoader()得到null
②启动类加载器用来加载jre和jre/lib目录下的核心库,如 java.lang.*,java.util.* 等
③启动类加载器没有父类加载器
④启动类加载器加载扩展类加载器和应用程序类加载器,成为他的父类加载器
2.扩展类加载器 Extension ClassLoader
①扩展类加载器用于加载JVM扩展目录中的类库,位于JDK安装目录下的jre/lib/ext目录中的jar包或目录。
②扩展类的加载器的父类加载器是启动类加载器。
③Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
3.应用程序类加载器Application Class Loader
①系统类加载器,它负责加载用户0类。
②它会搜索应用程序的类路径(包括用户定义的类路径和系统类路径),并加载类文件。
③是java应用程序默认的类加载器
4.自定义类加载器
当不满足开发时,可以自定义加载器。比如用网络加载Java类,为了保证传输中的安全性,采用了加密操作,那么以上3种加载器就无法加载这个类,这时候就需要自定义加载器。
实现步骤
①继承ClassLoader父类
②遵从双亲委派模式,重写findClass方法
③读取类文件的字节码
④调用父类的defineClass方法加载类
⑤使用者调用该类的加载器loadClass方法
二、类加载机制-双亲委派模式
1. 介绍
①JVM对class文件采用按需加载的方式,当需要该类的时候,jvm才会将class文件加载到内存产生class对象。
②在加载类的时候,采用双亲委派机制。把请求交给父类处理的一种任务委派模式
2. 工作原理
①如果一个类加载器接收到了类加载请求,它自己不会先去加载,会把这个请求委托给父类加载器去执行。
②如果父类还存在父类加载器,就继续向上委托。一直委托到启动类加载器:Bootstrap ClassLoader
③如果父类加载器可以完成加载任务,就返回成功结果。如果父类加载失败,就由子类自己加载,如果失败抛出ClassNotFoundException异常,这就是双亲委派模式
3. 优缺点
优点:
①保证安全性,层级关系代表优先级,也就是所有类的加载,优先给启动类加载器,这样就保证了核心类库类
②避免类的重复加载,如果父类加载器加载过了,子类加载器就没有必要再去加载了,确保一个类的全局唯一性
缺点:
①检查类是否加载的委派过程是单向的,即顶层的ClassLoader 无法访问底层的ClassLoader 所加载的类
②启动类加载器中的类为系统核心类,包括一些重要的系统接口,而在应用类加载器中,为应用类。 按照这种模式, 应用类访问系统类自然是没有问题,但是系统类访问应用类就会出现问题。
三、线程上下文类加载器
- 线程上下文类加载器就是双亲委派模型的破坏者,可以在执行线程中打破双亲委派机制的加载链关系,从而使得程序可以逆向使用类加载器
2.Java提供了很多核心接口的定义,这些接口被称为SPI接口,同时为了方便加载第三方的实现类,SPI提供了一种动态的服务发现机制(约定),只要第三方在编写实现类时,在工程内新建一个META-INF/services/目录并在该目录下创建一个与服务接口名称同名的文件,那么在程序启动的时候,就会根据约定去找到所有符合规范的实现类,然后交给线程上下文类加载器进行加载处理