目录
类加载器
类加载器负责加载class文件,将class文件字节码内容加载到内存中并将这些内容转换成方法区中的运行时数据结构。
JVM怎么判断文件是不是class文件?class文件开头有固定的标志“cafe babe”
ClassLoader只负责将class文件加载,至于是否执行由Execution Engine决定。
类加载器分为四种:C++写的启动类加载器(bootstrap)、Java写的扩展类加载器(Extension)、应用程序类加载器(AppClassLoader)、用户自定义类加载器
JDK自带的类(Object、String、ArrayList等)使用的是Bootstrap加载器,如果是自定义的类使用的是AppClassLoad类加载器,Extension加载器负责把自定义的类库加载进来。
上图打印了三个类加载器。
第一个是应用程序加载器。
第二个是扩展类加载器。
第三个是启动类(根)类加载器。
类加载器的工作流程
类加载器分为加载、链接、初始化三步骤
链接又包括验证、准备、解析三步
- 加载
通过类的全限定类名获取到该类的.class文件并加载到内存=》把二进制流的.class文件转换成方法区数据结构=》并在内存中创建一个class对象,作为方法区中这个类对外提供访问的入口。
- 链接
验证(Verify):确保class文件中的字节流包含的信息符合当前虚拟机的要求,利用沙箱安全机制保证文件的安全性。
准备(Prepare):为类中的静态字段分配内存,并设置默认的初始化值。比如int类型初始值是0.final修饰的常量不会被分配,因为它们在编译时就被分配值了
解析(Resolve):将常量池内的符号引用转换为实际引用的过程。如果引用符号指向一个为被加载的类,那解析将触发此类的加载
- 初始化
将类的构造方法init()的过程。编译器会自动收集类中所有类变量的赋值动作和静态代码块中的语句,合并起来,这就是int方法。
若该类具有父类,父类的init方法会先于子类的init方法执行
双亲委派机制
什么是双亲委派机制
双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载。
类加载器执行的流程
.class文件会通过类加载器,类加载器收到类加载的请求后,将这个请求向上委托给父类加载器去完成,父类加载器不会去执行,它会一直向上委托最终到根加载器。如果根加载器能够加载这个类(即rt.jar)包中有这个类,该类就会被根加载器加载,否则抛出异常,通知子类加载器进行加载。
根加载器加载不了有两个原因。一是rt.jar包中没有加载的main方法,二是方法是用比Java底层的语言C或C++写的,java程序获取不到
大部分我们自定义的类都是通过应用程序加载器加载的,但是如果应用程序加载器也加载不了,就会报Class Not Found~异常
BOOT==>EXC==>APP
举例
1.使用JDK提供的类
报错如下
原因是String类在根加载器中被找到,它会执行rt.jar包中String类,不会执行我们自定义的main方法
2.大多数自定义的类
程序并未报错,.class文件依次检查根加载器、扩展类加载器、应用程序加载器,最后从应用程序加载器加载.class文件,输出结果。
tomcat是使用了双亲委派机制吗
tomcat既用到了双亲委派机制,又不完全是双亲委派机制。因为tomcat用来创建多个容器。如果不同容器jar使用的不一样。比如spring2.1和spring2.5。双亲委派机制只能使用一个jar包加载。
而tomcat的加载分为3部分
第一部分橘黄色基于双亲委派,找到了应用程序类加载器。第二部分自定义的Common类加载器会找到catalina加载器和share加载器。第三部分share加载器会根据具体要求创建不同的容器
share之后是webapp类加载器,webapp之后是jsp类加载器(用来热部署用)