类加载器
Class Loader是通过loadClass加载类,有如下几步:
- 加载:从硬盘上读取字节码文件,使用到时才会加载;
- 验证:校验字节码文件的正确性;
- 准备:给类的静态变量分配内存,并赋予默认值。注意,这里的默认值不是在代码里变量的初始值;
- 解析:将符号引用替换为直接引用,该阶段会把一些静态方法替换为指向数据所存内存的指针或句柄等,这时所谓的静态链接过程,动态链接时在程序运行期间完成的将符号引用替换为直接引用;
- 初始化:对静态变量初始化指定的值,此时才进行代码中的赋值操作;
????????类被加载到方法区后包含运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例的引用等信息。
????????对应class实例的引用:在类加载到方法区后,会创建一个对应的Class类型的对象放到堆中,作为开发人员访问方法区中类定义的入口和切入点。
????????注意:jar包或war包不是一次性加载所有类,而是在使用的时候加载。
类加载器和双亲委派机制
Java中有如下几种类加载器:
- 引导类加载器:负责加载JRE的lib目录下的核心类库,如rt.jar、charsets.jar等
- 扩展类加载器:负责加载lib目录下ext目录中的Jar包
- 应用程序类加载器:即加载ClassPath目录下的类,即加载我们应用程序相关的类
- 自定义加载器:负责加载自定义路径下的类包
什么是双亲委派机制
????????双亲委派机制是Java中的一种类加载机制。双亲委派机制是当加载一个类时,先由父类加载,父类加载不到时再由子类加载。
????????这种机制的好处是避免了类的重复加载,提高了类加载的效率和安全性。同时,它也为Java提供了一种扩展机制,允许开发人员自定义类加载器,实现特定的加载策略。
为什么要设计双亲委派机制?
- 沙箱安全机制:如自己写的java.lang.String.class类不会被加载,这样可以防止核心API库被随意篡改。
- 避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性
tomcat的几个主要类加载器: - commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
- catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
- sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
- WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见,比如加载war包里相关的类,每个war包应用都有自己的WebappClassLoader,实现相互隔离,比如不同war包应用引入了不同的spring版本,这样实现就能加载各自的spring版本;
????????从途中的委派关系中可以看出:
CommonClassLoader能加载的类都可以被CatalinaClassLoader和SharedClassLoader使用,从而实现了公有类库的共用,而CatalinaClassLoader和SharedClassLoader自己能加载的类则与对方相互隔离。
WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。
而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃;当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的热加载功能。
????????每个webappClassLoader加载自己目录下的class文件,不会传递给父类加载器,打破了双亲委派机制。