加载器

Java类加载器

从J2SE1.2开始,JVM使用了三种类加载器:bootstrap类加载器、extension类加载器和system类加载器。

这三个加载器是父子关系,其中bootstrap类加载器在顶端,而system加载器在结构的最底层。

其中bootstrap类加载器用于引导JVM,一旦调用java.exe程序,bootstrap类加载器就开始工作。因此,它必须使用本地代码实现,然后加载JVM需要的类到函数中。另外,它还负责加载所有的Java核心类,例如java.lang和java.io包。另外bootstrap类加载器还会查找核心类库如rt.jar、i18n.jar等,这些类由JVM和操作系统决定。

extension类加载器负责加载标准扩展目录下面的类。这样就可以使得编写程序变得简单,只需把JAR文件拷贝到扩展目录下面即可,类加载器会自动的在下面查找。不同的供应商提供的扩展类库是不同的,Sun公司的JVM的标准扩展目录是/jdk/jre/lib/ext。

这样,JVM使用哪个类加载器?答案在于委派模型(delegationmodel),这是出于安全原因。每次一类需要加载,system类加载器首先调用。但是,它不会马上加载类。相反,它委派该任务给它的父类-extension类加载器。extension类加载器也把任务委派给它的父类bootstrap类加载器。因此,bootstrap类加载器总是首先加载类。如果bootstrap类加载器不能找到所需要的类的extension类加载器会尝试加载类。如果扩展类加载器也失败,system类加载器将执行任务。如果系统类加载器找不到类,将会抛出一个java.lang.ClassNotFoundException异常。

tomcat为什么要自定义classloader

你可以通过扩扩展抽象类:java.lang.ClassLoader来实现自己的类加载器。为什么Tomcat需要自己的类加载器?

  • 实现某些特定的规则(首先是要实现servlet规范中对类加载的要求,其次是实现不同web app的类隔离)
  • 缓存某些已经被加载的类
  • 提前加载将要被使用的类

servlet规范中对类加载要求如下:
This specification defines a hierarchical structure used for deployment and packaging purposes that can exist in an open file system, in an archive file, or in some other form. It is recommended, but not required, that servlet containers support this structure as a runtime representation.

Web applications can be packaged and signed into a Web ARchive format (WAR) file using the standard Java archive tools. For example, an application for issuetracking might be distributed in an archive file called issuetrack.war. When packaged into such a form, a META-INF directory will be present which contains information useful to Java archive tools. This directory must not be directly served as content by the container in response to a Web client’s request, though its contents are visible to servlet code via the getResource andgetResourceAsStream calls on the ServletContext. Also, any requests to access the resources in META-INF directory must be returned with a SC_NOT_FOUND(404) response.

tomcat的classloader

1、System — 这个classloader通常是由CLASSPATH这个环境变量初始化的,通过这个classloader加载的所有类,都对tomcat自身的类, 以及所有web应用的类可见。但是,标准的tomcat启动脚本($CATALINA_HOME/bin/catalina.bat),完全无视默认的CLASSPATH环境变量,而是加载了以下3个.jar


$CATALINA_HOME/bin/bootstrap.jar — Contains the main() method that is used to initialize the Tomcat server, and the class loader implementation classes it depends on.

$CATALINA_HOME/bin/tomcat-juli.jar — Logging implementation classes. These include enhancement classes to java.util.logging API, known as Tomcat JULI, and a package-renamed copy of Apache Commons Logging library used internally by Tomcat.

$CATALINA_HOME/bin/commons-daemon.jar — The classes from Apache Commons Daemon project.(这个类不是直接在$CATALINA_HOME/bin/catalina.bat里加进来的,不过在bootstrap.jar的 manifest文件中包含进来了)

2、Common — 这个classloader加载的类,对tomcat的类和web app的类都是可见的。通常来说,应用程序的类不应该放在这里。该加载器的加载路径是在$CATALINA_BASE/conf /catalina.properties文件里,通过common.loader属性来定义的

common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar

3、WebappX — 该classloader加载所有WEB-INF/classes里的类,以及WEB-INF/lib里的jar

该classloader就有意违反了上述的委托模型,它首先看WEB-INF/classes和WEB-INF/lib里是否有请求的类,而不是委托parent classloader去加载。但是,JRE里定义的类不能被覆盖(比如java.lang.String),以及Servlet API会明确地被忽略。

从web app的角度来看,类或者资源加载是按照以下的顺序来查找的:
Bootstrap classes of your JVM(rt.jar)
System class loader classes(bootstrap.jar、tomcat-juli.jar、commons-deamon.jar)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
Common class loader classes (在$CATALINA_HOME/lib里的jar包)

posted on 2016-06-13 16:34  cbwleft  阅读(224)  评论(0)    收藏  举报