1. tomcat类加载思维导向图
2. java 类加载思维导向图
3. tomcat类加载顺序
当应用需要到某个类时,则会按照下面的顺序进行类加载:
1 使用bootstrap引导类加载器加载,加载jvm所需的基础类
2 使用system系统类加载器加载,加载tomcat启动类等相关
3 使用应用类加载器在WEB-INF/classes中加载,加载部署的项目
4 使用应用类加载器在WEB-INF/lib中加载,加载部署的项目依赖的jar
5 使用common类加载器在CATALINA_HOME/lib中加载, 加载tomcat依赖的一些通用jar,例如servlet.jart
4. tomcat所有的加载器
5. 源码分析
tomcat启动类 Bootstrap
涉及类加载器
ClassLoader commonLoader = null; ClassLoader catalinaLoader = null; ClassLoader sharedLoader = null;
类加载器初始化
从main方法开始
public static void main(String args[]) { synchronized (daemonLock) { if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { // 初始化 bootstrap.init(); } 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); } } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); // 启动 } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start(); if (null == daemon.getServer()) { System.exit(1); } } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
start启动之后,调用start()方法
/**
* Start the Catalina daemon.
* @throws Exception Fatal start error
*/
public void start() throws Exception {
if (catalinaDaemon == null) {
init();
}
Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
method.invoke(catalinaDaemon, (Object [])null);
}
调用Init()方法
/** * Initialize daemon. * @throws Exception Fatal initialization error */ public void init() throws Exception { initClassLoaders(); // 打破双亲委托加载机制 Thread.currentThread().setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method if (log.isDebugEnabled()) log.debug("Loading startup class"); // 初始化Catalina Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.getConstructor().newInstance(); // Set the shared extensions class loader if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class<?> paramTypes[] = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); catalinaDaemon = startupInstance; }
private void initClassLoaders() { try { // 先初始化CommonLoader commonLoader = createClassLoader("common", null); if (commonLoader == null) { // no config file, default to this loader - we might be in a 'single' env. commonLoader = this.getClass().getClassLoader(); } // CommonLoader为parent类加载器 catalinaLoader = createClassLoader("server", commonLoader); // CommonLoader为parent类加载器 sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { handleThrowable(t); log.error("Class loader creation threw exception", t); System.exit(1); } }
此处给出类加载器的关系