几年的编程生涯,多少积累了些技术经验。是时候更深入的研究和总结一下了。就拿最常用的tomcat 7为例。废话不多说,下面开始干活。
1. 从官网download下源码:
http://mirrors.hust.edu.cn/apache/tomcat/tomcat-7/v7.0.65/src/apache-tomcat-7.0.65-src.zip;
解压Tomcat源码,如解压到D:\share\apache-tomcat-7.0.59-src。
2. 用ant编译源码。可以download官网也可以用eclipse自带的ant编译。
这里直接用eclipse导入源码编译。
eclipse –> new java project,起一个工程名为Tomcat7,然后import 源码到工程目录下。
这里还要将Tomcat7工程下的build.properties.default重命名为build.properties,并编辑修改base.path=E:/eclipseWork/Tomcat7/repository。
右键build.xml–>run as Ant Build,执行ant编译,这里注意编译环境选择JDK1.6,选JDK1.7会报错。成功会生成output目录。
还要加入依赖的jar包:jaxrpc-1.1.jar,org.eclipse.jdt.core-3.7.1.jar,wsdl4j-1.6.2.jar。
3. 运行。整个工程的入口在Bootstrap.java main方法里。
执行 右键run as:在VM arguments参数加上
-Dcatalina.home=”E:\eclipseWork\Tomcat7\output\build”,启动完成。
- 启动过程分析。
整个程序的入口是Bootstrap.main()这个引导加载类。
查看main方法源码大致如下:
public static void main(String args[]) {
...
Bootstrap bootstrap = new Bootstrap();
bootstrap.init();
daemon.load(args);
daemon.start();
...
}
可以看出,程序的启动分三步,初始化init、加载load和启动start。
bootstrap.init();方法代码:
public void init() {
initClassLoaders();
Thread.currentThread().setContextClassLoader(catalinaLoader);
Class<?> startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();
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() {
commonLoader = createClassLoader("common", null);
commonLoader=this.getClass().getClassLoader();
catalinaLoader = createClassLoader("server", commonLoader);
sharedLoader = createClassLoader("shared", commonLoader);
}
可以看出初始化首先初始化几个类加载器classLoader,利用反射实例化一个Catalina类实例,并把刚刚刚初始化的classLoader设置为成员变量。
private void load(String[] arguments)
throws Exception {
// Call the load() method
String methodName = "load";
Object param[];
Class<?> paramTypes[];
paramTypes = null;
param = null;
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
method.invoke(catalinaDaemon, param);
}
public void start()
throws Exception {
if( catalinaDaemon==null ) init();
Method method = catalinaDaemon.
getClass().getMethod("start", (Class [] )null);
method.invoke(catalinaDaemon, (Object [])null);
}
load和start方法都是通过调用刚才实例化catalina实例的对应load, start方法。可以看出整个程序的实际启动工作其实是在Catalina类中实现。那么为什么要这么做呢,而不是直接用Catalina启动?其目的就是隐藏该类实例,让应用程序不可见。