tomcat的启动从bootstrap的main方法開始,在main方法中主要是做了三件事,调用init方法初始化自己。调用catalinaDaemon对象

的setAwait方法设置它的await属性为true,最后调用自己的start方法。

首先看看init方法:

  public void init()
throws Exception
{ // Set Catalina path
setCatalinaHome();
setCatalinaBase(); //初始化三个类载入器
initClassLoaders();  //线程构造后将从它的父线程中继承对应的上下文类载入器. 假设在整个应用中你不做不论什么特殊设置,
        //全部的线程将都以系统类载入器(system classloader)作为自己的线程上下文类载入器.
        //这里从Bootstrap构造的线程都会继承改线程的上下文类载入器
Thread.currentThread().setContextClassLoader(catalinaLoader); //载入conf下的catalina.properties配置文件下的common.loader和server.loader所指定的类。由于server.loader为空时
//catalinaLoader和commonLoader是指向的同一对象,不为空时commonLoader是catalinaLoader的父类。
SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method
if (log.isDebugEnabled())
log.debug("Loading startup class");
Class<? > startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.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; }

这里的主要内容就是调用了initClassLoaders();初始化了commonLoader,catalinaLoader。sharedLoader三个类载入器。它们是bootstrap的

成员变量。并通过SecurityClassLoad.securityClassLoad(catalinaLoader)这步代码来载入conf/catalina.properties文件下common.loader,

server.loader,shared.loade三个属性指定的jar包和class。securityClassLoad会通过一系列环境变量替换等处理来找到相关的类并载入它们。

最后一段代码初始化Catalina对象,再设置它的父类载入器为sharedLoader。

这里的一些疑问稍后再说。

先看看initClassLoaders()方法:

initClassLoaders源代码:
private void initClassLoaders() {
try {
commonLoader = createClassLoader("common", null);//1,创建commonLoader类载入器
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);//2,
sharedLoader = createClassLoader("shared", commonLoader);//3,
} catch (Throwable t) {
handleThrowable(t);
log.error("Class loader creation threw exception", t);
System.exit(1);
}
}

第一步是通过commonkeyword初始化了一个commonLoader对象。

进到createClassLoader方法中:

 private ClassLoader createClassLoader(String name, ClassLoader parent)
throws Exception {
String value = CatalinaProperties.getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
return parent;
value = replace(value);
........
ClassLoader classLoader = ClassLoaderFactory.createClassLoader
(repositories, parent);
........
return classLoader;
}

这里应该非常清楚,CatalinaProperties.getProperty(name + ".loader");就是获取配置文件中的属性的方法。

value = replace(value)替换环境变量

等一系列的转换获取了一些类路径的url最后将这些url传给ClassLoaderFactory.createClassLoader方法。

CommonclassLoader和其它两个类载入器都

是通过该方法获取的,它们是一个StandardClassLoader实例。

StandardClassLoader仅仅是简单的从URLClassLoader继承,并实现了

StandardClassLoaderMBean接口来实现JMX监控。

所以能够觉得这三个类载入器就是URLClassLoader对象。

createClassLoader(repositories, parent),事实上就是调用了URLClassLoader的构造方法,传入类路径的URL集合和父载入器。

假设打开

conf/catalina.properties配置文件。server.loader,shared.loade默觉得空。从createClassLoader方法中if推断就能够知道

commonLoader == catalinaLoader == sharedLoader。

这里先说一点设置这三个类载入器的用意,以后再用源代码证明。commonLoader被用来设置为catalinaLoader和sharedLoader的父载入器。

catalinaLoader用来载入tomcat自身程序所须要的类。sharedLoader用来载入一些webapp文件夹下的程序共享的class。并被WebappClassLoader

(用户web程序的类载入器)设置为父类(从这里就能够知道web程序的类是怎么实现相互隔离,但又能够共享某些jar包的。由于类载入器在载入

类时会先让父载入器去载入,父载入器找不到的话就自己来载入,在这里sharedLoader和WebappClassLoader都有不同的载入路径,全部的

WebappClassLoader都继承自sharedLoader,所以他们共享了sharedLoader的载入路径)。

再来看看SecurityClassLoad.securityClassLoad(catalinaLoader):

public static void securityClassLoad(ClassLoader loader)
throws Exception { if( System.getSecurityManager() == null ){
return;
} loadCorePackage(loader);
loadCoyotePackage(loader);
loadLoaderPackage(loader);
loadRealmPackage(loader);
loadServletsPackage(loader);
loadSessionPackage(loader);
loadUtilPackage(loader);
loadValvesPackage(loader);
loadJavaxPackage(loader);
loadConnectorPackage(loader);
loadTomcatPackage(loader);
}

能够进每一个方法看下,它是载入了指定的一些类,注意这些类名是指定的。假设你放了自己的jar包在里面,那么它的载入就不是catalinaLoader完毕的。

最后就是初始化catalinaDaemon对象了,从最后一段代码能够看出catalinaDaemon被赋值为org.apache.catalina.startup.Catalina的实例。

而且通过反射调用调用了setParentClassLoader方法,參数是catalinaLoader。

    这里设置父载入器的用意是什么?以下是这种方法的源代码

 public void setParentClassLoader(ClassLoader parentClassLoader) {
this.parentClassLoader = parentClassLoader;
}

方法非常easy,看来问题不在这。在来看看Catalina的还有一个方法:

  public ClassLoader getParentClassLoader() {
if (parentClassLoader != null) {
return (parentClassLoader);
}
return ClassLoader.getSystemClassLoader();
}

事实上这里parentClassLoader属性不是说载入Catalina的类载入器的父类载入器。它仅仅是一个普通的属性。

在来看看哪里调用了getParentClassLoader,在StandardServer中有这样一个方法:

  @Override
public ClassLoader getParentClassLoader() {
if (parentClassLoader != null)
return (parentClassLoader);
if (catalina != null) {
return (catalina.getParentClassLoader());
}
return (ClassLoader.getSystemClassLoader());
}

然后他的下级组件StandardService:

  @Override
public ClassLoader getParentClassLoader() {
if (parentClassLoader != null)
return (parentClassLoader);
if (server != null) {
return (server.getParentClassLoader());
}
return (ClassLoader.getSystemClassLoader());
}

与之相应的都有一个setParentClassLoader方法。

    engin容器也有这种方法。

最后在WebappLoader中有个例如以下的方法:

 private WebappClassLoader createClassLoader()
throws Exception { Class<?> clazz = Class.forName(loaderClass);
WebappClassLoader classLoader = null; if (parentClassLoader == null) {
parentClassLoader = container.getParentClassLoader();
}
Class<? >[] argTypes = { ClassLoader.class };
Object[] args = { parentClassLoader };
Constructor<?> constr = clazz.getConstructor(argTypes);
classLoader = (WebappClassLoader) constr.newInstance(args); return classLoader; }

在这种方法中调用了org.apache.catalina.loader.WebappClassLoader的构造方法将容器container的parentClassLoader的属性最为classLoader的

父类载入器。这里能够得出结论从 Server 》 service 》 engin(container) 》没一个级别都在尝试设置parentClassLoader的值,而parentClassLoader

将作为WebappClassLoader的父类载入器。

也就是说parentClassLoader是针对WebappClassLoader而言的,而每一级别都在尝试改动它。·

如今已经介绍完了bootstrap的init方法,下一步是来介绍setAwait(true)方法的作用。

通过反射设置了Catalina的await属性为true。Catalina成功启动后

会通过检查该值来调用它的成员变量server的await方法:

public void start() {
........
if (await) {
await();
stop();
}
}
public void await() { getServer().await(); }

Catalina的成员变量server是一个StandardServer对象,通过调用该对象的await方法,会让他一直监控server.xml配置文件里的这段配置:

<Server port="8005" shutdown="SHUTDOWN">,所定义的端口发送过来的命令。

最后看看start方法:

public void start()
throws Exception {
if( catalinaDaemon==null ) init(); Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
method.invoke(catalinaDaemon, (Object [])null); }

start终于通过反射调用了catalinaDaemon(也就是Catalina)的start方法。

(这里看到的多处位置是通过反射调用catalinaDaemon的方法。

由于catalinaDaemon是一个object的引用指向的Catalina对象全部它仅仅能调用object对象的方法。想要调用Catalina的方法仅仅能通过反射。)

总结:bootstrap的主要任务就是初始化commonLoader。catalinaLoader,sharedLoader。通过catalinaLoader载入所须要的类。

初始化catalinaDaemon对象,调用它的start方法。



    疑问:bin/bootstrap.jar 和lib/catalina.jar中都有bootstrap,脚本调用的是bootstrap.jar中的main方法,bootstrap在初始三个类载入器后,

载入类时并没有载入org.apache.catalina.startup包下的类。也就是说尽管两个jar包都含有bootstrap类,但仅仅是系统的类载入器载入了

bin/bootstrap.jar里的bootstrap。而其它lib 文件夹下的全部的类都是有bootstrap里面的三个类载入器载入的。不清楚为什么这样做。

tomcat7源代码Bootstrap的更多相关文章

  1. session自己定义存储,怎样更好地进行session共享;读tomcat7源代码,org.apache.catalina.session.FileStore可知

    session自己定义存储.怎样更好地进行session共享: 读tomcat源代码,org.apache.catalina.session.FileStore可知 一.详见: 方法1 public ...

  2. centos6.5 安装jdk7和tomcat7

    JDK安装: 安装说明 系统环境:centos-6.5安装方式:rpm安装软件:jdk-7-linux-x64.rpm下载地址:http://www.oracle.com/technetwork/ja ...

  3. Tomcat7安装配置 for Ubuntu

    一.环境说明: 操作系统:Ubuntu 12.04.2 LTS Tomcat:apache-tomcat-7.0.52 二.下载 下载地址:http://tomcat.apache.org/ 这里下载 ...

  4. CentOS下安装Tomcat7

    1.检查java版本信息 #java -version java version "1.7.0_65" OpenJDK Runtime Environment (rhel-2.5. ...

  5. BOOTSTRAP定制

    1.补充:栅格系统中调整列的位置/顺序 (1)方法1:偏移量(col-*-offset-*) (2)方法2:对列进行push/pull操作 col-lg-pull-1        ~         ...

  6. ubuntu下Tomcat7的安装和配置

    和前几个软件一样,Tomcat 同样是由JAVA开发的,所以,在安装前一定要装好JDK. 大家可以到 http://tomcat.apache.org/download-70.cgi 下载最新的Tom ...

  7. Ubuntu 下 Tomcat7 的安装和配置

    tomcat下载地址:http://tomcat.apache.org/download-70.cgi 声明:下面的内容和原创笔者的博文的内容差不多,不一样的只是tomcat7的安装目录不同,我按照我 ...

  8. Linux下安装JDK7和TomCat7

    [BEGIN] 2016/9/9 14:20:49[root@rzhd jdk]# ll总用量 149916-rw-r--r-- 1 root root 153512879 9月 9 14:20 jd ...

  9. linux平台下Tomcat的安装与优化

    Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选.对于一个初学者来说,可以这样 ...

随机推荐

  1. 使用top工具,找出消耗CPU 较多的进程

    1.使用top工具,找出消耗CPU 较多的进程 [oracle@cuug ~]$ top top - 10:48:27 up 23:15,  4 users,  load average: 1.09, ...

  2. JavaScript--机选双色球

    <!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. Hive学习之一 《Hive的介绍和安装》

    一.什么是Hive Hive是建立在 Hadoop 上的数据仓库基础构架.它提供了一系列的工具,可以用来进行数据提取转化加载(ETL),这是一种可以存储.查询和分析存储在 Hadoop 中的大规模数据 ...

  4. qt实现类似QQ伸缩窗口--鼠标事件应用

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://blog.csdn.net/hiwubihe/article/details/38678305,qq:1269122125. 上一章 ...

  5. C++ 性能剖析 (三):Heap Object对比 Stack (auto) Object

    通常认为,性能的改进是90 ~ 10 规则, 即10%的代码要对90%的性能问题负责.做过大型软件工程的程序员一般都知道这个概念. 然而对于软件工程师来说,有些性能问题是不可原谅的,无论它们属于10% ...

  6. VBoxManage 命令行使用

    原文地址:http://cnjun939.blog.163.com/blog/static/78144538201251474311135/ 由于最近需研究virtualbox,看好看到上面的网址有, ...

  7. 再谈CMake与RPATH

    之前写过一篇<探讨CMake中关于RPATH的使用>,只要针对的方面是在编译生成之后(不包括安装的make install)如何去除RPATH的问题.今天给大家主要介绍一下如何让CMake ...

  8. Javascript中回调函数的学习笔记

    function a_b(kkis){ document.body.style.background ='red'; kkis(); } function fli(){ alert('######## ...

  9. Boost使用笔记(Smart_ptr)

    我是Word写的,复制过来实在懒得在排版了,有兴趣的朋友可以去我的百度文库看,谢谢 http://wenku.baidu.com/view/34e485e2f61fb7360b4c653e.html ...

  10. 极简易版专家聊天程序--JAVA练手

    呵呵,用JAVA包开发SOCKET连接,是很简单的呢~~~ DailyAdviceServer.java import java.io.*; import java.net.*; public cla ...