系统的启动流程:
tomcat通常从脚本启动,查看脚本可知,startup.sh中调用了catalina.sh进行启动,而在catalina.sh中,可以看到时启动了Bootstrap类
org.apache.catalina.startup.Bootstrap "$@" start
从bootstrap类的main方法开始启动,此类中有
private Object catalinaDaemon = null ;
protected ClassLoader commonLoader = null ;
protected ClassLoader catalinaLoader = null ;
等,首先new boostrap对象,调用init方法,init方法中先调用initClassLoader方法,获取 三种ClassLoader,分别是:commonLoader、catalinaLoader 、sharedLoader ,在此说明一句,如果commonLoader初始化失败,即没有config配置文件,则将bootstrap的Classloader赋值给commonLoader。
先从commonLoader说起,
String value = . getProperty(name + ".loader");
此处使用了CatalinaProperties类,这个类有
static{
loadProperties();
}
会随着类的加载而运行,加载了加载Catalina.Properties配置文件,通过字符串common.loader获取此属性文件对应的配置:
common.loader="${catalina.base}/lib", "${catalina.home}/lib/*.jar"
然后通过replace方法处理拿到的字符串,替换为对应config目录; D:\SVN\CodeLearning\Tomcat8\output\build/lib,根据四种模式:DIR JAR URL GLOB去扫描相应类,最后通过
ClassLoaderFactory. createClassLoader(repositories, parent)
方法,将String类型的加载路径字符串穿进去,在此方法中使用LinkedHashSet,扫描将要加载的类,对应四种不同的模式,然后将这个LinkedHashSet.toArray,赋值给链表,最后
return new URLClassLoader(array);
把要加载路径赋值进去,返回一个URLClassLoader,并加载各种类。所以commonLoader就是URLClassLoader。接上面的,如果没有config,则使用bootstrap的ClassLoader给commonLoader。
同理,catalinaLoader和sharedLoader的加载方式:
catalinaLoader = createClassLoader( "server", commonLoader );
sharedLoader = createClassLoader("shared" , commonLoader );
由此可见commonloader是其父类加载器。不过server.loader和sharedLoader在Catalina.properties中没配置属性。当调用 catalinaLoader = createClassLoader( “server” , commonLoader );
sharedLoader = createClassLoader(“shared” , commonLoader );
时,
String value = CatalinaProperties. getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
return parent;
由于properties文件没有对应的server.loader和shared.loader属性,古直接返回URLClassLoader加载器。
综上,三种加载器初始化完毕,调用Thread. currentThread().setContextClassLoader( catalinaLoader);
将catalinaLoader设置为当前线程的加载器。 然后调用
Class<?> startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina");
在加载catalina类,使用反射,调用其setParentClassLoader方法,参数为java.lang.ClassLoader.
然后调用catalina的isAwait和start方法,启动服务器。
Method method = catalinaDaemon.getClass().getMethod ("start" , (Class [] )null );