tomcat类加载机制
When Tomcat is started, it creates a set of class loaders that areorganized into the following parent-child relationships, where the parentclass loader is above the child class loader:
Bootstrap
|
System
|
Common
/ \
Webapp1 Webapp2 ...
Bootstrap — This class loader contains the basic runtime classes provided by the Java Virtual Machine, plus any classes from JAR files present in the SystemExtensions directory ($JAVA_HOME/jre/lib/ext
).Note: some JVMs may implement this as more than one class loader, or it may not be visible (as a class loader) at all.
System —This class loader is normally initialized from the contents of theCLASSPATH
environment variable。However, the standard Tomcat startup scripts ($CATALINA_HOME/bin/catalina.sh
or%CATALINA_HOME%\bin\catalina.bat
) totally ignore the contents of theCLASSPATH
environment variable itself, and instead build the System class loader from the following repositories:
$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. main函数启动
$CATALINA_BASE/bin/tomcat-juli.jar or $CATALINA_HOME/bin/tomcat-juli.jar — Logging implementation classes. These include enhancement classes tojava.util.logging
API, known as Tomcat JULI, and a package-renamed copy of Apache Commons Logging library used internally by Tomcat. Seelogging documentation for more details. 日志
$CATALINA_HOME/bin/commons-daemon.jar — The classes from Apache Commons Daemon project. This JAR file is not present in the CLASSPATH
built bycatalina.bat
|.sh
scripts, but is referenced from the manifest file ofbootstrap.jar.
Common—this class loader are defined by the common.loader
property in $CATALINA_BASE/conf/catalina.properties.
common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
WebappX — A class loader is created for each web application that is deployed in a single Tomcat instance. All unpacked classes and resources in the/WEB-INF/classes
directory of your web application, plus classes and resources in JAR files under the/WEB-INF/lib
directory of your web application, are made visible to this web application, but not to other ones.
该classloader就有意违反委托模型,它首先看WEB-INF/classes和WEB-INF/lib里是否有请求的类,而不是委托parent classloader去加载。但是,JRE里定义的类不能被覆盖(比如java.lang.String,但也有一些特例,如 XML parser components),以及Servlet API会明确地被忽略。
前面说的bootstrap、system、common,都遵循普通的委托模型
从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包)
tomcat类加载机制的建立过程:
由startup.bat 启动 catalina.bat,然后catalina.bat设置了CLASSPATH路径:
//------------------------------start: catalina.bat 设置CLASSPATH代码----------------------
set CLASSPATH= // 先设置为空
。。。。
rem Add on extra jar file to CLASSPATH
rem Note that there are no quotes as we do not want to introduce random
rem quotes into the CLASSPATH
if "%CLASSPATH%" == "" goto emptyClasspath
set "CLASSPATH=%CLASSPATH%;"
:emptyClasspath
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar"
//设置CLASSPATH=%CATALINA_HOME%\bin\bootstrap.jar
。。。
rem Add tomcat-juli.jar to classpath
rem tomcat-juli.jar can be over-ridden per instance
if not exist "%CATALINA_BASE%\bin\tomcat-juli.jar" goto juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar"
goto juliClasspathDone
//设置CLASSPATH=%CATALINA_HOME%\bin\bootstrap.jar+tomcat-juli.jar
//------------------------------end: catalina.bat 设置CLASSPATH代码----------------------
然后由catalina.bat 启动Bootstrap.java中的main方法:
在main方法中调用bootstrap.init()--->
public static void main(String args[]) { if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init();//全局的系统属性、初始化类加载器、通过反射得到Catalina实例 } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { // When running as a service the call to stop will be on a new // thread so make sure the correct class loader is used to prevent // a range of class not found exceptions. Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } 。。。。}
在init中调用initClassLoaders();
public void init() throws Exception { // Set Catalina path setCatalinaHome(); setCatalinaBase(); initClassLoaders(); 。。。。}
在initClassLoaders中建立起tomcat 的类加载机制
SystemClassLoader<-CommonLoader(<-catalinaLoader<-sharedLoader (已不再使用 ))
private void initClassLoaders() { try { commonLoader = createClassLoader("common", null);//null代表parent为SystemClassLoader,可以查看java源码 if( commonLoader == null ) { // no config file, default to this loader - we might be in a 'single' env. commonLoader=this.getClass().getClassLoader(); } Object appclassloader=commonLoader.getParent();//appclassloader catalinaLoader = createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { handleThrowable(t); log.error("Class loader creation threw exception", t); System.exit(1); } }