Java类加载器
类加载器(class loader)
用来加载 Java 类到 Java 虚拟机中。Java 源程序(.java 文件) 编译器编译后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。 基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例
类加载器分类
系统提供的
- 引导类加载器(bootstrap class loader):加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader。(C++实现,属虚拟机)lib/rt.jar
- 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。DIR:$JAVA_HOME/lib/ext
- 系统类加载器(system class loader):它根据(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
自定义
- 应用开发者自定义类加载器(Tomcat Web 容器)
Java双亲委派
当类加载器收到类加载任务,会先交给其父类加载器去完成加载,因此最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。
采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。
双亲委派优先父加载器加载, 但Java Servlet规范采用优先当前类加载器加载,加载失败再委托父代理加载
类加载器与 OSGi
OSGi™是 Java 上的动态模块系统。它为开发人员提供了面向服务和基于组件的运行环境,并提供标准的方式用来管理软件的生命周期。
OSGi 中的每个模块(bundle)都包含 Java 包和类。模块可以声明它所依赖的需要导入(import)的其它模块的 Java 包和类(通过 Import-Package),也可以声明导出(export)自己的包和类,供其它模块使用(通过 Export-Package
)。也就是说需要能够隐藏和共享一个模块中的某些 Java 包和类。这是通过 OSGi 特有的类加载器机制来实现的。OSGi 中的每个模块都有对应的一个类加载器。它负责加载模块自己包含的 Java 包和类。当它需要加载 Java 核心库的类时(以 java开头的包和类),它会代理给父类加载器(通常是启动类加载器)来完成。当它需要加载所导入的 Java 类时,它会代理给导出此 Java 类的模块来完成加载。模块也可以显式的声明某些 Java 包和类,必须由父类加载器来加载。只需要设置系统属性 org.osgi.framework.bootdelegation的值即可。
解决依赖冲突的主要技术,同时日常使用的热部署,热重载都是该类技术得以实现.项目模块化皆因此开始
参考资料
(IBM): https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html "深入探讨 Java 类加载器"
[掘金]: https://juejin.im/post/5b001f44518825428b390eee "JVM 面试知识整理"