tomcat为什么要违背双亲委托机制
- 什么是双亲委托机制
双亲委托的含义:
1) 加载的顺序固定: 引导类加载器—》扩展类加载器—》应用类加载器—-》自定义类加载器
2) 当我们使用扩展类加载器加载某个类的时候,若引导类加载器已经加载的该类,就不会继续加载过程
3) 下一级类加载器的加载过程依赖上一级类加载器
4)jdk核心class只能被加载一次
双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求时,子加载器才会尝试自己去加载。
- tomcat的类加载机制
- 双亲委托能否满足tomcat的业务需求
1) tomcat需要保证各个web项目的类独立加载,不同项目的相同jar可能版本不一致,需要保持依赖Jar相互独立
2) web容器依赖的类库与web项目依赖的类库隔离
3)jsp热部署的实现
默认的类加载机制需要保证class的唯一性,不能满足上述需求,也不能实现热部署。需要自定义类加载器。
4.tomcat 为什么要违背双亲委托机制
1) 双亲委托机制不能满足tomcat的业务需求
2) Webapp类加载器需要独立加载自身的class以及依赖的jar
3) 例如,webapp1依赖的spring版本为4.x,另一个依赖的spring版本为5.x. 如果使用双亲委托,那么spring的版本只能存在一个,没法满足这个需求
4) tomcat 自身依赖的jar可能和项目依赖的jar有重合的地方,比如servlet.jar, 此时优先webapp的jar加载
- tomcat如何解决class隔离问题
每个Webapp类加载器独立去加载WEB-INF/lib与WEB-INF/classes目录下的class或ja
线程上下文加载器: 父类加载器请求子类加载器去完成类加载的动作,完成逆向双亲委托加载流程。
线程上下文类加载器(Thread Context ClassLoader):这个类加载器可以通过java.lang.Thread类的setContextClassLoader方法进行设置。如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认即使应用程序类加载器。
- 源码实现
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized(JreCompat.isGraalAvailable() ? this : this.getClassLoadingLock(name)) {
if (log.isDebugEnabled()) {
log.debug("loadClass(" + name + ", " + resolve + ")");
}
Class<?> clazz = null;
this.checkStateForClassLoading(name);
// 从本地缓存中查找
clazz = this.findLoadedClass0(name);
if (clazz != null) {
if (log.isDebugEnabled()) {
log.debug(" Returning class from cache");
}
if (resolve) {
this.resolveClass(clazz);
}
return clazz;
}
// 从系统类加载器缓存中查找,已加载的类都会加入缓存
clazz = JreCompat.isGraalAvailable() ? null : this.findLoadedClass(name);
if (clazz != null) {
if (log.isDebugEnabled()) {
log.debug(" Returning class from cache");
}
if (resolve) {
this.resolveClass(clazz);
}
return clazz;
}
String resourceName = this.binaryNameToPath(name, false);
// 使用扩展类加载器加载,而没有使用系统类加载器,违背了双亲委托加载机制,目的是隔离
ClassLoader javaseLoader = this.getJavaseClassLoader();
boolean tryLoadingFromJavaseLoader;
try {
URL url;
if (this.securityManager != null) {
PrivilegedAction<URL> dp = new WebappClassLoaderBase.PrivilegedJavaseGetResource(resourceName);
url = (URL)AccessController.doPrivileged(dp);
} else {
url = javaseLoader.getResource(resourceName);
}
tryLoadingFromJavaseLoader = url != null;
} catch (Throwable var13) {
ExceptionUtils.handleThrowable(var13);
tryLoadingFromJavaseLoader = true;
}
Class var10000;
if (tryLoadingFromJavaseLoader) {
label218: {
try {
clazz = javaseLoader.loadClass(name);
if (clazz == null) {
break label218;
}
if (resolve) {
this.resolveClass(clazz);
}
var10000 = clazz;
} catch (ClassNotFoundException var15) {
break label218;
}
return var10000;
}
}
if (this.securityManager != null) {
int i = name.lastIndexOf(46);
if (i >= 0) {
try {
this.securityManager.checkPackageAccess(name.substring(0, i));
} catch (SecurityException var12) {
String error = sm.getString("webappClassLoader.restrictedPackage", new Object[]{name});
log.info(error, var12);
throw new ClassNotFoundException(error, var12);
}
}
}
boolean delegateLoad = this.delegate || this.filter(name, true);
if (delegateLoad) {
label219: {
if (log.isDebugEnabled()) {
log.debug(" Delegating to parent classloader1 " + this.parent);
}
try {
clazz = Class.forName(name, false, this.parent);
if (clazz == null) {
break label219;
}
if (log.isDebugEnabled()) {
log.debug(" Loading class from parent");
}
if (resolve) {
this.resolveClass(clazz);
}
var10000 = clazz;
} catch (ClassNotFoundException var17) {
break label219;
}
return var10000;
}
}
if (log.isDebugEnabled()) {
log.debug(" Searching local repositories");
}
label181: {
try {
clazz = this.findClass(name);
if (clazz == null) {
break label181;
}
if (log.isDebugEnabled()) {
log.debug(" Loading class from local repository");
}
if (resolve) {
this.resolveClass(clazz);
}
var10000 = clazz;
} catch (ClassNotFoundException var16) {
break label181;
}
return var10000;
}
if (delegateLoad) {
throw new ClassNotFoundException(name);
}
if (log.isDebugEnabled()) {
log.debug(" Delegating to parent classloader at end: " + this.parent);
}
try {
clazz = Class.forName(name, false, this.parent);
if (clazz != null) {
if (log.isDebugEnabled()) {
log.debug(" Loading class from parent");
}
if (resolve) {
this.resolveClass(clazz);
}
var10000 = clazz;
return var10000;
}
} catch (ClassNotFoundException var14) {
;
}
}
throw new ClassNotFoundException(name);
}
还没有评论,来说两句吧...