类加载过程
【加载】JVM把.class文件加载到方法区,生成构造函数、接口、静态变量(static)、常量(final)池、静态代码块
并在堆中生成对应的Class对象
【链接】将类的二进制代码合并到JVM的运行状态之中
• 验证
确保加载的类信息符合JVM规范,没有安全方面的问题
• 准备
正式为static变量分配内存并设置默认值(和Bean实例化很像),具体赋值在初始化阶段完成
• 解析
虚拟机常量池内的符号引用替换为直接引用(地址引用)的过程【初始化】如果发现其父类还没有进行过初始化,则需要先初始化其父类
顺序如下(其实很有规律)
1、父类的静态变量
2、父类的静态代码块
3、子类的静态变量
4、子类的静态代码块
5、父类的非静态变量
6、父类的非静态代码块
7、父类的构造方法
8、子类的非静态变量
9、子类的非静态代码块
10、子类的构造方法
.
双亲委派机制
自定义ClassLoader→AppClassLoader(自定义的类)→PlatformClassLoader(jre/lib/ext/*.jar)→BootClassLoader(jre/lib/rt.jar)
始终加载能找到的最上层的类(防止自定义String类等),这样保证了安全
为什么叫双亲委派?
名字翻译有问题
强行的解释是:自己定义的类要委派给ExtensionClassLoader
和BootstrapClassLoader
的“双亲”
Tomcat打破双亲委派机制
如何打破?
重写ClassLoader.loadClass
方法
源码👇
.
1 | protected Class<?> loadClass(String name, boolean resolve) |
自定义的ClassLoader
需要重写**loadClass和findClass
**方法
Tomcat 遵守双亲委派模型,每个WebAppClassLoader
加载自己目录下的class文件
.
为何打破?
隔离:部署在同一个容器中的不同应用A和B,例如A用了Spring2.5,B用了Spring3.5,如果A和B使用的是同一个类加载器,那么Web应用就会因为jar包覆盖而无法启动
性能:如果在一个Tomcat部署多个应用,他们都有相同的类库依赖,那么可以把相同的类库让
CommonClassLoader
进行加载