深入理解Java类加载器
https://blog.csdn.net/zhoudaxia/article/details/35824249
https://blog.csdn.net/zhoudaxia/article/details/35897057
- BootstrapClassLoader:只能用于加载JDK核心类库,系统变量为sun.boot.class.path下面的类。该目录下的%JAVA_HOME%/jre/lib/下的resources.jar;rt.jar等核心类库,该loader底层采用C++编写,自然你也就不能调用啦。
- ExtClassLoader :用于加载一些扩展类,系统变量为java.ext.dirs中的类。作用:加载开发者自己扩展类。
- AppClassLoader:用于加载用户类,这个就是java.class.path下的类,也就是我们自己编写出来的类。
其中这三个加载器顺序为BootstrapClassLoader>ExtClassLoader>AppClassLoader,为啥要这样设计?主要是为了扩展与安全。首先你将BootstrapClassLoader作为一个核心类加载器,只加载核心类,不与其他耦合在一起。并且为何要设计这三个加载器,就应该和双亲委派机制放在一起了。
何为双亲委派机制:简单来说就是当你需要加载类的时候,必须从顶级父加载器先加载,如果父加载不了,则交给子加载器。就相当于小孩子要做决定的时候,要先问问父亲怎么做。
为什么要有这种双亲委派机制:
保证唯一性:试想,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,多个类加载器都去加载这个类到内存中,系统中将会出现多个不同的Object类,那么类之间的比较结果及类的唯一性将无法保证.
保证安全:由于所有的用户类都会先通过bootstrapclassloader 查看里面有没有该类资源,有则直接安徽或者加载,从而保证了底层的类一定是预先加载的,这样可以对虚拟机的安全得到了很好的保证。
关于自定义类加载模型
思考以下情景:
- 首先,是为了区分同名的类:假定存在一个应用服务器,上面部署着许多独立的应用,同时他们拥有许多同名却不同版本的类库。试想,这时候 jvm 该怎么加载这些类同时能尽可能的避免掉类加载时对同名类的差异检测呢?当然是不同的应用都拥有自己独立的类加载器了。
- 其次,是为了更方便的加强类的能力:类加载器可以在 load class 时对 class 进行重写和覆盖,在此期间就可以对类进行功能性的增强。比如添加面向切面编程时用到的动态代理,以及 debug 等原理。怎么样达到仅修改一个类库而不对其他类库产生影响的效果呢?一个比较方便的模式就是每个类库都可以使用独立的类加载器
小结:
jvm 需要有不同的类加载器,因为它一方面允许你在一个 jvm 里运行不同的应用程序,另一方面方便你独立的对不同类库进行运行时增强。