tomcat为什么要违背双亲委托机制

清疚 2023-06-07 15:25 91阅读 0赞
  1. 什么是双亲委托机制

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA2Mjc4NDA_size_16_color_FFFFFF_t_70

双亲委托的含义:

1) 加载的顺序固定: 引导类加载器—》扩展类加载器—》应用类加载器—-》自定义类加载器

2) 当我们使用扩展类加载器加载某个类的时候,若引导类加载器已经加载的该类,就不会继续加载过程

3) 下一级类加载器的加载过程依赖上一级类加载器

4)jdk核心class只能被加载一次

双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求时,子加载器才会尝试自己去加载。

  1. tomcat的类加载机制

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA2Mjc4NDA_size_16_color_FFFFFF_t_70 1

  1. 双亲委托能否满足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加载

  1. tomcat如何解决class隔离问题

每个Webapp类加载器独立去加载WEB-INF/lib与WEB-INF/classes目录下的class或ja

线程上下文加载器: 父类加载器请求子类加载器去完成类加载的动作,完成逆向双亲委托加载流程。

线程上下文类加载器(Thread Context ClassLoader):这个类加载器可以通过java.lang.Thread类的setContextClassLoader方法进行设置。如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认即使应用程序类加载器。

  1. 源码实现
  1. public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
  2. synchronized(JreCompat.isGraalAvailable() ? this : this.getClassLoadingLock(name)) {
  3. if (log.isDebugEnabled()) {
  4. log.debug("loadClass(" + name + ", " + resolve + ")");
  5. }
  6. Class<?> clazz = null;
  7. this.checkStateForClassLoading(name);
  8. // 从本地缓存中查找
  9. clazz = this.findLoadedClass0(name);
  10. if (clazz != null) {
  11. if (log.isDebugEnabled()) {
  12. log.debug(" Returning class from cache");
  13. }
  14. if (resolve) {
  15. this.resolveClass(clazz);
  16. }
  17. return clazz;
  18. }
  19. // 从系统类加载器缓存中查找,已加载的类都会加入缓存
  20. clazz = JreCompat.isGraalAvailable() ? null : this.findLoadedClass(name);
  21. if (clazz != null) {
  22. if (log.isDebugEnabled()) {
  23. log.debug(" Returning class from cache");
  24. }
  25. if (resolve) {
  26. this.resolveClass(clazz);
  27. }
  28. return clazz;
  29. }
  30. String resourceName = this.binaryNameToPath(name, false);
  31. // 使用扩展类加载器加载,而没有使用系统类加载器,违背了双亲委托加载机制,目的是隔离
  32. ClassLoader javaseLoader = this.getJavaseClassLoader();
  33. boolean tryLoadingFromJavaseLoader;
  34. try {
  35. URL url;
  36. if (this.securityManager != null) {
  37. PrivilegedAction<URL> dp = new WebappClassLoaderBase.PrivilegedJavaseGetResource(resourceName);
  38. url = (URL)AccessController.doPrivileged(dp);
  39. } else {
  40. url = javaseLoader.getResource(resourceName);
  41. }
  42. tryLoadingFromJavaseLoader = url != null;
  43. } catch (Throwable var13) {
  44. ExceptionUtils.handleThrowable(var13);
  45. tryLoadingFromJavaseLoader = true;
  46. }
  47. Class var10000;
  48. if (tryLoadingFromJavaseLoader) {
  49. label218: {
  50. try {
  51. clazz = javaseLoader.loadClass(name);
  52. if (clazz == null) {
  53. break label218;
  54. }
  55. if (resolve) {
  56. this.resolveClass(clazz);
  57. }
  58. var10000 = clazz;
  59. } catch (ClassNotFoundException var15) {
  60. break label218;
  61. }
  62. return var10000;
  63. }
  64. }
  65. if (this.securityManager != null) {
  66. int i = name.lastIndexOf(46);
  67. if (i >= 0) {
  68. try {
  69. this.securityManager.checkPackageAccess(name.substring(0, i));
  70. } catch (SecurityException var12) {
  71. String error = sm.getString("webappClassLoader.restrictedPackage", new Object[]{name});
  72. log.info(error, var12);
  73. throw new ClassNotFoundException(error, var12);
  74. }
  75. }
  76. }
  77. boolean delegateLoad = this.delegate || this.filter(name, true);
  78. if (delegateLoad) {
  79. label219: {
  80. if (log.isDebugEnabled()) {
  81. log.debug(" Delegating to parent classloader1 " + this.parent);
  82. }
  83. try {
  84. clazz = Class.forName(name, false, this.parent);
  85. if (clazz == null) {
  86. break label219;
  87. }
  88. if (log.isDebugEnabled()) {
  89. log.debug(" Loading class from parent");
  90. }
  91. if (resolve) {
  92. this.resolveClass(clazz);
  93. }
  94. var10000 = clazz;
  95. } catch (ClassNotFoundException var17) {
  96. break label219;
  97. }
  98. return var10000;
  99. }
  100. }
  101. if (log.isDebugEnabled()) {
  102. log.debug(" Searching local repositories");
  103. }
  104. label181: {
  105. try {
  106. clazz = this.findClass(name);
  107. if (clazz == null) {
  108. break label181;
  109. }
  110. if (log.isDebugEnabled()) {
  111. log.debug(" Loading class from local repository");
  112. }
  113. if (resolve) {
  114. this.resolveClass(clazz);
  115. }
  116. var10000 = clazz;
  117. } catch (ClassNotFoundException var16) {
  118. break label181;
  119. }
  120. return var10000;
  121. }
  122. if (delegateLoad) {
  123. throw new ClassNotFoundException(name);
  124. }
  125. if (log.isDebugEnabled()) {
  126. log.debug(" Delegating to parent classloader at end: " + this.parent);
  127. }
  128. try {
  129. clazz = Class.forName(name, false, this.parent);
  130. if (clazz != null) {
  131. if (log.isDebugEnabled()) {
  132. log.debug(" Loading class from parent");
  133. }
  134. if (resolve) {
  135. this.resolveClass(clazz);
  136. }
  137. var10000 = clazz;
  138. return var10000;
  139. }
  140. } catch (ClassNotFoundException var14) {
  141. ;
  142. }
  143. }
  144. throw new ClassNotFoundException(name);
  145. }

发表评论

表情:
评论列表 (有 0 条评论,91人围观)

还没有评论,来说两句吧...

相关阅读