hailai 发表于 2017-1-19 09:30:45

Tomcat 源码学习 之 Bootstrap



类名
Bootstrap


继承关系                          



关联类

Catalina
ClassLoaderFactory
MBeanServer




实现功能

创建Tomcat的classLoader机制
代理Catalina方法调用
初始化全局变量CATALINA_HOME_PROP 和 CATALINA_BASE_PROP



  分析
  Tomcat启动
  Tomcat中共有两个类用于Server的启动,Bootstrap和Catalina。作为Bootstrap的主要工作,是代理Catalina内部方法的调用,其本身并不执行任何Server的启动/关闭操作。可以说,Bootstrap和Catalina做了许多重复的工作。初次看代码的读者,都会有这样的困惑:为什么要把Server启动分到两个类里面来做呢?
  这么做的目的主要有两个:
  1. 将Catalina及其相关的类加载脱离System ClassLoader。
  2. 支持多种Tomcat启动方式。
  作为Web Server,Tomcat需要采用和应用程序不同的类加载方式,并确保不同权限的类在内存中有效的隔离。关于Tomcat的类加载机制,我们等下会提到。
  同时,通过这种分离,可以确保Tomcat支持多种启动方式,包括standalone,多实例以及嵌入式的方式。
  全局变量
  Bootstrap类里包含两个很重要的全局变量:CATALINA_HOME_PROP 和 CATALINA_BASE_PROP。当我们通过正常的启动方式启动Tomcat时,这两个变量所指向的是同一个URL:${TOMCAT_HOME}。
  那我们为什么需要两个变量来存储同一个值呢?这是因为当我们同时启动多个Tomcat实例(在不同端口上)时,不同实例的CATALINA_BASE_PROP将会指向不同的URL。
  基本上来说,CATALINA_HOME_PROP指向公用信息的位置,即bin和lib的父目,而 CATALINA_BASE_PROP指向每个Tomcat目录私有信息的位置,即conf、logs、temp、webapps和work的父目录。
  由于我们运行单个实例时,两者是相同URL,所以变量值也相同。而当我们运行多个Tomcat实例时,两者的不同就显现出来了。
  类加载机制
  Bootstrap类中定义了三个不同的ClassLoader: commonLoader,catalinaLoader 和 sharedLoader。并通过构造这样一个ClassLoader树,以保证模块的类库的私有性:
  +---------------------------------------+
  |            Bootstrap              
  |                |                  
  |             System               
  |                |                  
  |             Common                
  |            /         \            
  |        Catalina     Shared        
  |                          /       \        
  |             WebApp1     WebApp2   
  +---------------------------------------+
  - Bootstrap
  - 载入JVM自带的类和$JAVA_HOME/jre/lib/ext/*.jar
  - System
  - 载入$CLASSPATH/*.class
  - Common
  - 载入$CATALINA_HOME/common/...,它们对TOMCAT和所有的WEB APP都可见
  - Catalina
  - 载入$CATALINA_HOME/server/...,它们仅对TOMCAT可见,对所有的WEB APP都不可见
  - Shared
  - 载入$CATALINA_HOME/shared/...,它们仅对所有WEB APP可见,对TOMCAT不可见
  - WebApp
  - 载入ContextBase?/WEB-INF/...,它们仅对该WEB APP可见
  最终,Tomcat会将这些类加载器全部用JMX加载并管理。
  Bootstrap利用ClassLoaderFactory来创建ClassLoader, 这个类里面最主要的接口如下:

    public static ClassLoader createClassLoader(File unpacked[], File packed[], final ClassLoader parent)
public static ClassLoader createClassLoader(List<Repository> repositories, final ClassLoader parent)
   通过传入URL列表,以及父加载机制,ClassLoaderFactory产生一个StandardClassLoader的实例。StandardClassLoader类继承于URLClassLoader,并实现了一个空的MBean接口StandardClassLoaderMBean,这样就保证了所有的ClassLoader的实例都可以被JMX来维护。
  StandardClassLoader的代码如下:

public class StandardClassLoader
extends URLClassLoader
implements StandardClassLoaderMBean {
public StandardClassLoader(URL repositories[]) {
super(repositories);
}
public StandardClassLoader(URL repositories[], ClassLoader parent) {
super(repositories, parent);
}
}

public interface StandardClassLoaderMBean {
// Marker interface
}
  将ClassLoader放入JMX的代码:

      // Retrieving MBean server
MBeanServer mBeanServer = null;
if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
} else {
mBeanServer = ManagementFactory.getPlatformMBeanServer();
}
// Register the server classloader
ObjectName objectName =
new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
mBeanServer.registerMBean(classLoader, objectName);
 
 
 
  Catalina调用
Bootstrap类对于所有Catalina方法的调用都是通过反射机制来实现的。采用这种方式的好处就是,将两者有机的分离开来,为将来的扩展提供便利。
页: [1]
查看完整版本: Tomcat 源码学习 之 Bootstrap