1,什么是双亲委派机制,为什么要用这种机制
"向上委派"和"向下查找"是指类加载器在加载Java类时的一种机制。
"向上委派"指的是当一个类加载器需要加载某个类时,它会先请求其父类加载器去尝试加载该类。如果父类加载器无法加载该类,再由当前类加载器自己进行加载。
"向下查找"则相反,指的是当一个类被加载时,在其中需要引用其他类时,会由当前类加载器首先尝试去加载这些类,如果无法加载,则会交由其子类加载器去尝试加载。
通过这种机制,每个类加载器都优先向上委派请求父类加载器来尝试加载类,而且若父类加载器已经成功加载了某个类,子类加载器就不会再次加载,从而避免重复加载,提高了加载效率。同时,当需要查找某个类时,也可以通过向下查找的方式快速定位到对应的类。
2,tomcat为什么要违反双亲委派规则
Tomcat为了实现Web应用程序的隔离和独立性,采用了自定义类加载器来加载Web应用程序中的类文件。在这个过程中,如果Web应用程序包含重复的类文件,则Tomcat会根据其自己的查找规则加载这些类,而不是采用Java标准的双亲委派机制。
这种做法的主要原因是,每个Web应用程序都有自己的类文件和依赖项,如果采用传统的父子层次关系进行加载,则可能会导致冲突和错误。例如,如果两个Web应用程序都使用了相同版本的JAR文件,但其中一个应用程序使用了修订版的JAR文件,那么使用传统的双亲委派机制将无法处理这种情况,并且可能会导致类冲突和错误。
Tomcat使用的自定义类加载器可以根据一定的规则先从本地的WEB-INF/classes目录和WEB-INF/lib目录下查找类文件,如果没有找到,则再由其父类加载器(通常是系统类加载器)进行查找。这样就可以避免类名冲突和错误,并确保每个Web应用程序都能够在独立的环境中运行。
以下是Tomcat Web应用程序类加载器的示例代码:
public class WebappClassLoader extends URLClassLoader {
private static final String[] TRIGGERS = {"org.apache.catalina.", "org.apache.tomcat."};
public WebappClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
@Override
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// 检查类是否已经被加载
Class<?> c = findLoadedClass(name);
if (c != null) {
return c;
}
// 检查是否是系统类
for (String trigger : TRIGGERS) {
if (name.startsWith(trigger)) {
// 系统类
return super.loadClass(name, resolve);
}
}
// 查找WEB-INF/classes和WEB-INF/lib目录下的类文件
try {
URL url = findResource(name.replace('.', '/') + ".class");
if (url != null) {
byte[] bytes = getBytes(url);
c = defineClass(name, bytes, 0, bytes.length);
if (resolve) {
resolveClass(c);
}
return c;
}
} catch (IOException e) {
// 忽略
}
// 如果还是没有找到,交给父类加载器进行加载
return super.loadClass(name, resolve);
}
}
在这个例子中,WebappClassLoader类继承了URLClassLoader,并重写了loadClass方法。在loadClass方法中,先检查所加载的类是否已经被加载过,如果没有则检查是否为系统类,如果是则交由父类加载器进行加载;否则(即不是系统类)再根据自己的规则查找WEB-INF/classes和WEB-INF/lib目录下的类文件。如果还没有找到,则交由父类加载器进行加载。这样就实现了自定义的类加载;