当前位置:   article > 正文

tomcat 类加载器_tomcat 设置类加载器

tomcat 设置类加载器

tomcat 类加载器

                 

官网:Apache Tomcat 10 (10.0.14) - Class Loader How-To

        

                                  

***************

java 类加载器

                 

双亲委派模型(java8及之前类加载模型)

                         

              

类加载器说明

  1. # 启动类加载器
  2. 加载JAVA_HOME/lib目录、参数-Xbootclasspath指定路径下的类
  3. 文件名需要能被虚拟机识别(如rt.jar、tools.jar),如果不能识别,即使在路径下也不会被加载
  4. # 拓展类加载器
  5. 加载JAVA_HOME/lib/ext目录、java.ext.dirs系统变量指定目录下的类
  6. 可将具有通用性的类库放置在ext目录里来java se的功能
  7. # 应用程序类加载器
  8. 加载用户类路径(classpath)上的所有类,可以在代码中直接使用这个类加载器
  9. 如果用户没有自定义类加载器,默认使用该类加载器加载用户自定的类

                    

双亲委派类加载流程

  1. 类加载器接收到类加载请求,如果当前类加载器加载过类,则直接返回;
  2. 否则,将请求往上抛,直到启动类加载器,由启动类加载器加载;
  3. 如果加载不了,则将类加载请求往下抛,由下层类加载器加载类,直到加载到类为止;
  4. 如果请求抛至直到最初接收到类加载请求的类加载器,还是加载不了类,抛出ClassNotFoundException异常

                     

ClassLoader

  1. public abstract class ClassLoader {
  2. ...
  3. protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
  4. {
  5. synchronized (getClassLoadingLock(name)) {
  6. // First, check if the class has already been loaded
  7. //如果加载过,从缓存中直接获取类
  8. Class<?> c = findLoadedClass(name);
  9. if (c == null) { //如果缓存中没有
  10. long t0 = System.nanoTime();
  11. try {
  12. if (parent != null) { //如果存在父类加载器
  13. c = parent.loadClass(name, false); //父类加载器加载类
  14. } else {
  15. c = findBootstrapClassOrNull(name); //不存在,说明当前类加载器为启动类加载器,
  16. //由启动类加载器加载类
  17. }
  18. } catch (ClassNotFoundException e) {
  19. // ClassNotFoundException thrown if class not found
  20. // from the non-null parent class loader
  21. }
  22. if (c == null) { //如果加载不到
  23. // If still not found, then invoke findClass in order
  24. // to find the class.
  25. long t1 = System.nanoTime();
  26. c = findClass(name); //当前类加载器加载类,找不到则抛出异常
  27. // this is the defining class loader; record the stats
  28. sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
  29. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
  30. sun.misc.PerfCounter.getFindClasses().increment();
  31. }
  32. }
  33. if (resolve) {
  34. resolveClass(c);
  35. }
  36. return c;
  37. }
  38. }
  39. ...
  40. }

                  

破坏双亲委派模型

  1. 双亲委派模型在java2引入,为向前兼容,提供了findClass类加载类;
  2. 引入线程上下文类加载器,父类加载器委托子类加载器加载类;
  3. 模块化热部署:每个模块都有一个类加载器,实现程序热替换;
  4. java9引入模块化系统,拓展类加载器被平台类加载器替代,加载流程也做出调整

                   

java9 类加载器

                         

平台类加载器、应用程序类加载器在接收到类加载请求时,如果可以判断类所属的模块,优先将类加载请求抛给对应的类加载器

               

BuiltInClassLoader:启动类加载器、平台类加载器、应用程序类加载器均继承该类

  1. public class BuiltinClassLoader extends SecureClassLoader
  2. ...
  3. @Override
  4. protected Class<?> loadClass(String cn, boolean resolve)
  5. throws ClassNotFoundException
  6. {
  7. Class<?> c = loadClassOrNull(cn, resolve);
  8. if (c == null) //如果最终没加载到类,抛出ClassNotFoundException异常
  9. throw new ClassNotFoundException(cn);
  10. return c;
  11. }
  12. /**
  13. * A variation of {@code loadClass} to load a class with the specified
  14. * binary name. This method returns {@code null} when the class is not
  15. * found.
  16. */
  17. protected Class<?> loadClassOrNull(String cn, boolean resolve) {
  18. synchronized (getClassLoadingLock(cn)) {
  19. // check if already loaded
  20. Class<?> c = findLoadedClass(cn); //如果已经加载过该类,直接返回
  21. if (c == null) {
  22. // find the candidate module for this class
  23. LoadedModule loadedModule = findLoadedModule(cn);
  24. //查找类所属的模块
  25. if (loadedModule != null) { //找到类所属模块,直接用对应的类加载器加载
  26. // package is in a module
  27. BuiltinClassLoader loader = loadedModule.loader();
  28. if (loader == this) { //是当前类加载器,则用当前类加载器加载
  29. if (VM.isModuleSystemInited()) {
  30. c = findClassInModuleOrNull(loadedModule, cn);
  31. }
  32. } else {
  33. // delegate to the other loader
  34. c = loader.loadClassOrNull(cn); //如果不是,抛给对应的类加载器
  35. }
  36. } else {
  37. // check parent
  38. if (parent != null) { //如果没找到对应的模块,使用父类加载器加载
  39. c = parent.loadClassOrNull(cn);
  40. }
  41. // check class path
  42. if (c == null && hasClassPath() && VM.isModuleSystemInited()) {
  43. c = findClassOnClassPathOrNull(cn);
  44. } //如果没加载到类,当前类加载器在类路径中加载
  45. }
  46. }
  47. if (resolve && c != null)
  48. resolveClass(c);
  49. return c;
  50. }
  51. }
  52. ...
  53. }

                  

               

***************

tomcat 类加载器

                 

                         

             

类加载器默认配置:catalina.properties

  1. common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
  2. server.loader=
  3. shared.loader=

              

Bootstrap:启动类加载器

  1. This class loader contains the basic runtime classes provided by the Java Virtual
  2. Machine, plus any classes from JAR files present in the System Extensions directory
  3. ($JAVA_HOME/jre/lib/ext)
  4. bootstrap类加载器加载jvm基础类、$JAVA_HOME/jre/lib/ext目录下的拓展类

          

System:系统类加载器

  1. This class loader is normally initialized from the contents of the CLASSPATH
  2. environment variable. All such classes are visible to both Tomcat internal classes,
  3. and to web applications.
  4. # 该类加载器通常在CLASSPATH路径下初始化,加载的类对tomcat内部类、应用程序可见
  5. However, the standard Tomcat startup scripts ($CATALINA_HOME/bin/catalina.sh or
  6. %CATALINA_HOME%\bin\catalina.bat) totally ignore the contents of the CLASSPATH
  7. environment variable itself, and instead build the System class loader from the
  8. following repositories:
  9. $CATALINA_HOME/bin/bootstrap.jar、
  10. $CATALINA_BASE/bin/tomcat-juli.jar or $CATALINA_HOME/bin/tomcat-juli.jar
  11. $CATALINA_HOME/bin/commons-daemon.jar
  12. # 标准启动方式(sh脚本启动、bat脚本启动)会忽略classpath下的内容,
  13. # 从$CATALINA_HOME/bin目录下的几个jar包创建系统类加载器

          

common:common类加载器

  1. This class loader contains additional classes that are made visible to both Tomcat
  2. internal classes and to all web applications
  3. # common类加载器加载的类对tomcat内部类、应用程序均可见
  4. Normally, application classes should NOT be placed here. The locations searched by
  5. this class loader are defined by the common.loader property in $CATALINA_BASE/conf
  6. /catalina.properties. The default setting will search the following locations in
  7. the order they are listed:
  8. unpacked classes and resources in $CATALINA_BASE/lib
  9. JAR files in $CATALINA_BASE/lib
  10. unpacked classes and resources in $CATALINA_HOME/lib
  11. JAR files in $CATALINA_HOME/lib
  12. #通常应用程序的类不应该放置在common类加载器的加载目录
  13. #common类加载器加载目录在catalina.properties中设置,
  14. #默认加载顺序:$CATALINA_BASE/lib解压的类、$CATALINA_BASE/lib中的jar包
  15. $CATALINA_HOME/lib解压的类、$CATALINA_HOME/lib中的jar包

               

webappX:web应用类加载器

  1. A class loader is created for each web application that is deployed in a single
  2. Tomcat instance. All unpacked classes and resources in the /WEB-INF/classes
  3. directory of your web application, plus classes and resources in JAR files under
  4. the /WEB-INF/lib directory of your web application, are made visible to this web
  5. application, but not to other ones.
  6. # web应用类加载器由应用程序创建
  7. # web应用类加载器会加载/WEB-INF/classes下的解压类、/WEB-INF/lib下的jar包
  8. # 加载的类只对本应用可见,对其他应用不可见

                  

web应用类加载器委派规则

  1. As mentioned above, the web application class loader diverges from the default Java
  2. delegation model (in accordance with the recommendations in the Servlet
  3. Specification, version 2.4, section 9.7.2 Web Application Classloader).
  4. #web应用类加载器打破java双亲委派模型规则
  5. When a request to load a class from the web application's WebappX class loader is
  6. processed, this class loader will look in the local repositories first, instead of
  7. delegating before looking. There are exceptions. Classes which are part of the JRE
  8. base classes cannot be overridden. There are some exceptions such as the XML parser
  9. components which can be overridden using the appropriate JVM feature which is the
  10. endorsed standards override feature for Java <= 8 and the upgradeable modules
  11. feature for Java 9+. Lastly, the web application class loader will always delegate
  12. first for Jakarta EE API classes for the specifications implemented by Tomcat
  13. (Servlet, JSP, EL, WebSocket).
  14. #web应用类加载器收到类加载请求时,首先在本地目录中查找类,不会进行委派(java基础类除外)
  15. #特殊情况:java基础类不会被覆盖(基础类加载请求始终会委派给bootClassLoader加载)、
  16. xml解析工具覆盖措施:java8(含)以下使用enndorsed机制覆盖、java9以上使用可升级模块特性覆盖
  17. Jakarta EE API classes类总是会进行委派,不会在本地进行加载
  18. All other class loaders in Tomcat follow the usual delegation pattern
  19. #其他的类加载器都遵循双亲委派规则

                

从web应用类加载器角度看,类、资源文件加载顺序如下

  1. #默认委派规则
  2. Bootstrap classes of your JVM
  3. /WEB-INF/classes of your web application
  4. /WEB-INF/lib/*.jar of your web application
  5. System class loader classes (described above)
  6. Common class loader classes (described above)
  7. #强制使用双亲委派规则:<Loader delegate="true"/> (server.xml中配置)
  8. Bootstrap classes of your JVM
  9. System class loader classes (described above)
  10. Common class loader classes (described above)
  11. /WEB-INF/classes of your web application
  12. /WEB-INF/lib/*.jar of your web application

                    

xml 解析工具覆盖

  1. Starting with Java 1.4 a copy of JAXP APIs and an XML parser are packed inside the
  2. JRE. This has impacts on applications that wish to use their own XML parser.
  3. #从java4开始,JAXP APIs、XML parser内置在jre里面,用户使用自定义的解析工具的方式需要变更
  4. In old versions of Tomcat, you could simply replace the XML parser in the Tomcat
  5. libraries directory to change the parser used by all web applications. However,
  6. this technique will not be effective when you are running modern versions of Java,
  7. because the usual class loader delegation process will always choose the
  8. implementation inside the JDK in preference to this one.
  9. #在老的版本里面,用户可直接替换tomcat目录里面的xml解析工具
  10. #java4解析工具内置到jre里面后,这种直接替换的方式方式不起作用
  11. Java <= 8 supports a mechanism called the "Endorsed Standards Override Mechanism"
  12. to allow replacement of APIs created outside of the JCP (i.e. DOM and SAX from
  13. W3C). It can also be used to update the XML parser implementation. For more
  14. information, see: http://docs.oracle.com/javase/1.5.0/docs/guide/standards
  15. /index.html. For Java 9+, use the upgradeable modules feature.
  16. #java8(含)以下提供endorsed机制进行替换
  17. #java9以上使用可升级的模块特性进行替换
  18. Tomcat utilizes the endorsed mechanism by including the system property setting
  19. -Djava.endorsed.dirs=$JAVA_ENDORSED_DIRS in the command line that starts the
  20. container. The default value of this option is $CATALINA_HOME/endorsed. This
  21. endorsed directory is not created by default. Note that the endorsed feature is no
  22. longer supported with Java 9 and the above system property will only be set if
  23. either the directory $CATALINA_HOME/endorsed exists, or the variable
  24. JAVA_ENDORSED_DIRS has been set.
  25. #endorsed使用:-Djava.endorsed.dirs=$JAVA_ENDORSED_DIRS
  26. #tomcat endorsed默认目录:$CATALINA_HOME/endorsed,这个目录默认不会自动创建
  27. #java9及以上不支持endorsed机制
  28. Note that overriding any JRE component carries risk. If the overriding component
  29. does not provide a 100% compatible API (e.g. the API provided by Xerces is not 100%
  30. compatible with the XML API provided by the JRE) then there is a risk that Tomcat
  31. and/or the deployed application will experience errors.
  32. #覆盖jre组件会有风险,如果提供的api不能100%和jre提供的xml api适配,
  33. #tomcat服务器、tomcat部署的应用可能会报错

              

              

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/845259
推荐阅读
  

闽ICP备14008679号