Tomcat ClassLoader打破双亲委派源码解析
作者:汤卜
这篇文章主要为大家介绍了Tomcat ClassLoader打破双亲委派源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
java加载类
java加载类的时候需要使用类加载器,开发人员可以定制类的加载器,比如tomcat就扩展了自己的类加载器。这篇文章结合代码研究一下jdk类的加载器和tomcat的类加载
先上图复习一下
来看一下jdk的ClassLoader的代码
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 本类加载器从缓存里面拿取已经加载过的ClassLoader Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { // 父类为BootStrapClassLoader的classLoader 的parent变量为空 if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } .......... }
注意看一下核心代码,实际上parent只要不为空就由parent来加载,因此当类未加载的时候,总是由上级来优先加载。
tomcat的类加载
首先来看一下tomcat的类加载器,tomcat写了一个自己的类加载器,看下基类WebappClassLoaderBase的实现
@Override public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { ................ // 从缓存里面取,不影响加载顺序,请着重忽略 clazz = findLoadedClass0(name); .......... clazz = findLoadedClass(name); ......... /** * The bootstrap class loader used to load the JavaSE classes. In some * implementations this class loader is always <code>null</code> and in * those cases {@link ClassLoader#getParent()} will be called recursively on * the system class loader and the last non-null result used. */ // 注意看注释,javaseLoader是bootstrap加载的,所以javaseLoader是扩展类加载器 ClassLoader javaseLoader = getJavaseClassLoader(); clazz = javaseLoader.loadClass(name); boolean delegateLoad = delegate || filter(name, true); // (2) Search local repositories if (log.isDebugEnabled()) { log.debug(" Searching local repositories"); } try { // 重写了findClass方法,从项目中的lib和class里加载 clazz = findClass(name); if (clazz != null) { if (log.isDebugEnabled()) { log.debug(" Loading class from local repository"); } if (resolve) { resolveClass(clazz); } return clazz; } } catch (ClassNotFoundException e) { // Ignore } // (3) Delegate to parent unconditionally if (!delegateLoad) { if (log.isDebugEnabled()) { log.debug(" Delegating to parent classloader at end: " + parent); } try { // 继承于SystemClassLoader该类,所以这个parent是SystemClassLoader, clazz = Class.forName(name, false, parent); if (clazz != null) { if (log.isDebugEnabled()) { log.debug(" Loading class from parent"); } if (resolve) { resolveClass(clazz); } return clazz; } } catch (ClassNotFoundException e) { // Ignore } } } throw new ClassNotFoundException(name); }
把顺序相关外的代码省略了,注意看注释。
因此来梳理一下加载顺序
1.找ext加载器,ext会优先走BootStrap加载器,加载java核心类库
2.ext加载不到就去走重写的findClass,走web项目的lib包和class目录,加载项目的class
3.重写的findClass找不到,就去系统类加载器SystemClassLoader来加载。
tomcat为什么要重写这个ClassLoader呢
1.最重要的就是做隔离性,不同的 web包引入不同的jar包版本,如果重写类的加载顺序,统一走SystemClassloader加载,那么只会加载一个类在内存,另外一个版本的class永远也不会加载进内存。无法实现web项目的隔离
2.可以针对一个应用进行重新部署,一个应用一个加载器,需要重新部署,就把这个classLoader加载的类重新加载就可以了
所以看起来打破双亲委派这种大名头的知识,看一下源码就清晰了,养成阅读源码习惯就可以
以上就是Tomcat ClassLoader打破双亲委派源码解析的详细内容,更多关于Tomcat ClassLoader双亲委派的资料请关注脚本之家其它相关文章!