类加载器
jvm支持两种类型的加载器,分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)
从概念上来说,自定义加载器一般指的是程序中由开发人员自定义的一类类加载器,单java虚拟机规范缺没有这么定义,而是将所有派生与抽象类ClassLoader的类加载期都划分为自定义加载器。
常见的有4种类加载器:
- 引导加载器(Bootstrap ClassLoader)
- 加载java的核心类库(JAVA_HOME/jre/lib/rt.jar、resourecs.jar或sum.boot.class.path路径下的内容),用于提供jvm自身需要的类
- 由C++实现,并不继承java.lang.ClassLoader,嵌套在jvm内部
- 加载扩展类加载器和应用程序类加载器,并指定为他的父类加载器
- 出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类。
- 扩展类加载器(Extensions ClassLoader)
- 它负责加载JRE的扩展目录,jre/lib/ext目录下或者由java.ext.dirs系统属性指定的目录中的JAR包的类。
- 由Java语言实现,是sun.misc.Launcher的内部类,父加载是java.net.URLClassLoader,间接继承java.lang.ClassLoader
- 系统(应用程序)类加载器(System/Application ClassLoader)
- 加载环境变量classpath或系统属性java.class.path指定路径下的类库
- 程序中默认的类加载,一般来说,java应用中的类都由他来加载
- 由Java语言实现,是sun.misc.Launcher的内部类,父加载是java.net.URLClassLoader,间接继承java.lang.ClassLoader
- 自定义类加载器(User Defined ClassLoader)
- 意义
- 隔离类加载
- 在多模块,多中间件应用中,来解决类冲突,模块之间,类加载的独立
- 修改类加载的方式
- 个性化加载,动态加载,不想通过扩展类加载器和系统类加载器
- 扩展加载源
- 比如数据库
- 防止源码泄漏
- 加密
- 隔离类加载
- 实现
- 可以继承URLClassLoader
- 可以继承ClassLoader,重载findClass方法,不破坏双亲委派机制
- 意义
类加载器关系
sun.misc.Launcher,它是一个java虚拟机的入口应用
- abstract ClassLoader 抽象类
- loadClass(String) 调用入口,内部调用父类的loadClass和findClass
- findClass(String) 本类获取类对象,调用defineClass
- defineClass(byte[],int,int) 从二进制字节中获取类对象
- resolveClass(Class<?>) 解析类对象
- SecureClassLoader
- URLClassLoader
- findClass(String)
- ExtClassLoader 扩展类加载器
- AppClassLoader 系统类加载器
- loadClass(String) 加载类,会调用上层加载器
- URLClassLoader
类加载器直接是包含关系,上层包含下层,下层加载的类,上册是不知道的。
- 引导加载器 由于是本地方法,所以无法获取地址和对象,加载
- 扩展类加载器
- 系统(应用程序)类加载器
- 自定义类加载器(不破坏双亲委派机制的情况下,自定义一般属于最下层)
- 系统(应用程序)类加载器
- 扩展类加载器
双亲委派机制
- 防止重复加载类
- 加载器加载时,入口是在最下层的,逐层向上委托
- 上层加载过,下层就不会加载
- 上层无法加载,下层才会自己去加载
- 防止class被篡改
- 这样导致重新写一个与java核心一样的同包同名的类是无法被加载的
- java.lang.String 沙箱安全机制
- 加密过的class,也无法被加载,需自定义加载器
- 这样导致重新写一个与java核心一样的同包同名的类是无法被加载的
1 | protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{ |
获取ClassLoader的路径
- 获取当前类的ClassLoader
- clazz.getClassLoader()
- 获取当前线程上下文的ClassLoader
- Thread.currentThread().getContextClassLoader()
- 获取系统的ClassLoader
- ClassLoader.getSystemClassLoader()
- 获取调用者的ClassLoader
- DriverManager.getCallerClassLoader()
class对象是否为同一个类
必要条件:
- 类的完整类名必须一致,包括包名
- 加载这个类的ClassLoader(实例对象的ClassLoader)必须相同
类的主动使用和被动使用
- 主动
- 创建类的实例
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射
- 初始化一个类的子类
- java虚拟机启动时被表名为启动类的类
- jdk7开始童工动态语言支持
- java.lang.invoke.MethodHandle实例的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic句柄对应的类没有初始化,则初始化
- 被动
- 除了以上主动,其余都是被动,都不会导致类的初始化