代码片段:
org.apache.catalina.startup.Bootstrap#main()
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; }
Bootstrap static {}
Bootstrap有一个静态代码块, 用来获取tomcat的工作目录和安装目录.
默认情况下, 是工作目录和安装目录是相同的, 也可以配置成不同的.
// 这里有一个静态代码块 static { // Will always be non-null // 获取用户目录 String userDir = System.getProperty("user.dir"); // Home first // tomcat的安装目录 String home = System.getProperty(Constants.CATALINA_HOME_PROP); File homeFile = null; if (home != null) { File f = new File(home); try { homeFile = f.getCanonicalFile(); } catch (IOException ioe) { homeFile = f.getAbsoluteFile(); } } if (homeFile == null) { // First fall-back. See if current directory is a bin directory // in a normal Tomcat install File bootstrapJar = new File(userDir, "bootstrap.jar"); if (bootstrapJar.exists()) { File f = new File(userDir, ".."); try { homeFile = f.getCanonicalFile(); } catch (IOException ioe) { homeFile = f.getAbsoluteFile(); } } } if (homeFile == null) { // Second fall-back. Use current directory File f = new File(userDir); try { homeFile = f.getCanonicalFile(); } catch (IOException ioe) { homeFile = f.getAbsoluteFile(); } } catalinaHomeFile = homeFile; System.setProperty(Constants.CATALINA_HOME_PROP, catalinaHomeFile.getPath()); // Then base String base = System.getProperty(Constants.CATALINA_BASE_PROP); if (base == null) { // 一般情况下, 工作目录 = 安装目录 catalinaBaseFile = catalinaHomeFile; } else { File baseFile = new File(base); try { baseFile = baseFile.getCanonicalFile(); } catch (IOException ioe) { baseFile = baseFile.getAbsoluteFile(); } catalinaBaseFile = baseFile; } System.setProperty(Constants.CATALINA_BASE_PROP, catalinaBaseFile.getPath()); }
bootstrap.init()
public void init() throws Exception { // 创建了三个自己的类加载器 // commonLoader catalinaLoader sharedLoader 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"); // 反射创建 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); // 调用 Catalina#setParentClassLoader(sharedLoader), 设置属性 // Catalina.parentClassLoader method.invoke(startupInstance, paramValues); catalinaDaemon = startupInstance; }
initClassLoaders
/** * 创建了三个自己的类加载器 commonLoader catalinaLoader sharedLoader */ private void initClassLoaders() { try { 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(); } catalinaLoader = createClassLoader("server", commonLoader); // 给 webapp 用 sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { handleThrowable(t); log.error("Class loader creation threw exception", t); System.exit(1); } }
创建的三个类加载器并不是三个独立的类加载器, 其结构关系为:
setParentClassLoader
//org.apache.catalina.startup.Catalina#setParentClassLoader public void setParentClassLoader(ClassLoader parentClassLoader) { this.parentClassLoader = parentClassLoader; }
tomcat 初始化时, 代码逻辑还是比较简单的.
主要干了两件事:
1. 调用 initClassLoaders() , 创建了三个自己的类加载器
2. 反射创建了 Catalina 类, 并调用了其 setParentClassLoader() 方法, 将 sharedLoader 类加载器设置进去