简介
双亲委派加载机制的意义是什么呢?
减少相同类的创建,代码功能的完整性和一致性。还有个原因就是有人恶意创建一些类来对程序进行恶意攻击。
而在谈双亲委派之前,还是要谈谈类的加载过程。
类的加载
1、验证阶段;JVM会校验.class文件是否符合JVM规范。
2、准备阶段;给静态变量赋值给默认值。如果是加final的静态变量,则直接赋值完成。比如public static final a=1; 那么直接赋值给a变量为1;请注意通过new创建的对象并不是在这里复制。
3、解析阶段;把字节码的常量池中的一些引用给变成直接引用,这样的变量都可以被访问到了。
4、初始化;把静态变量的值给初始化。
双亲委派
根据类的加载描述,双亲委派的这个过程应该是在验证的时候完成的。
class文件进行双亲委派的时候,是一层层开始进行寻找和加载的。
比如现在要加载一个类,其实就是从应用加载起开始,一级级向上委派,直到到最顶层的父类,然后开始判断是否有改类,如果有就进行加载,没有就继续向下进行加载,直到加载到该类为止,如果没有加载到就抛出来ClassNotFoundException。
总结:
其实就是越是顶层的父类的优先级越高,即同样的加载器有同样的包名和类名,那么肯定是父类先加载这个类,而下面的子加载器则不会加载到这个类。
自定义加载器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
public FileSystemClassLoader(String rootDir) {
this.rootDir = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String path = rootDir + File.separatorChar
+ name.replace('.', File.separatorChar) + ".class";
byte[] bytecode = null;;
try (InputStream input = new FileInputStream(path)) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int readSize = 0;
while ((readSize = input.read(buffer)) != -1) {
byteStream.write(buffer, 0, readSize);
}
bytecode = byteStream.toByteArray();
} catch (FileNotFoundException | IOException e) {
e.printStackTrace();
}
if (bytecode == null) {
throw new ClassNotFoundException("class name: " + name);
} else {
return defineClass(name, bytecode, 0, bytecode.length);
}
}
}
问题
当一个Tomcat部署多个项目时,如果多个项目包含全限定名相同的类该怎么办?
Tomcat会为每个web应用创建一个类加载器,这几个类加载器之间是隔离的。