赞
踩
tomcat源码 https://github.com/huyufan1995/tomcat.git
Tomcat 8 的源码解读,需要大家对tomcat有一定了解,剩下的就是理解就好,个人认为源码里面 mybatis 和 tomcat 就简单理解而言还是算简单的。 tomcat8 大量用了模板设计模式。tomcat8去掉了Bio的默认实现。
请大家认真观看下图:脑子有个映像,下面会详细讲解
每个Tomcat都只有一个Server,表示整个服务环境。一个Server中可以有多个Service。Server就掌管着多个Service的死活
Service是对外提供服务的,一个Server中可以有多个Service,每一个Service中可以有多个Connector和一个Container(Engine)
Connector主要用来接收请求,解析请求内容,封装request和response,然后将准备好的数据交给Container处理
Container就是我们常说的容器,里面可以有多个Host,一个host表示一个虚拟主机,就是一个对应一个WebApps. 最后Container处理完请求之后会将响应内容返回给Connecter,再由Connecter返回给客户端
Connector 和 conntainer
connector架构:最底层使用的是Socket进行连接的,Request和Response是按照Http协议来封装的,所以Connector同时需要实现TCP/IP协议和Http协议
Connector中具体用事件处理器来处理请求【ProtocoHandler】,不同的ProtocoHandler代表不同的连接类型【所以一个Service中可以有多个Connector】 例如:Http11Protocol使用普通的Socket来连接的,Http11NioProtocol使用NioSocket连接。 Endpoint用于处理底层Socket的网络连接,用来实现Tcp/Ip协议。 Acceptor:用于监听和接收请求。 Handler:请求的初步处理,并且调用Processor AsynTimeout:检查异步的Request请求是否超时 Processor用于将Endpoint接收Socket封装成Request,用来实现HTTP协议 Adapter 用于将Request交给Container 进行具体处理,即将请求适配到Servlet容器 Container 架构:Container就是一个Engine。Container用于封装和管理Servlet,以及具体处理Request请求
context:就是一个webapp 就是一个应用。
wrapper就是一个servlet包装器
Engine:Container(容器/引擎), 用来管理多个站点,一个Service最多只能有一个Engine
Host:虚拟主机,一个Container可以有多个虚拟主机
Context:一个应用程序,就是我们平时开发的一个项目,或者说是一套web引用程序
Wrapper:用来包装Servlet,每一个Wraper都包装着一个Servlet
EndPoint:
提供字节流给Processor
监听通信端口,是对传输层的抽象,用来实现 TCP/IP 协议的。 对应的抽象类为AbstractEndPoint,有很多实现类,比如NioEndPoint,JIoEndPoint等。在其中有两个组件,一个 是Acceptor,另外一个是SocketProcessor。 Acceptor用于监听Socket连接请求,SocketProcessor用于处理接收到的Socket请求。
Processor:
提供Tomcat Request对象给Adapter
Processor是用于实现HTTP协议的,也就是说Processor是针对应用层协议的抽象。 Processor接受来自EndPoint的Socket,然后解析成Tomcat Request和Tomcat Response对象,最后通过Adapter 提交给容器。 对应的抽象类为AbstractProcessor,有很多实现类,比如AjpProcessor、Http11Processor等。
Adapter:
提供ServletRequest给容器
ProtocolHandler接口负责解析请求并生成 Tomcat Request 类。 需要把这个 Request 对象转换成 ServletRequest。 Tomcat 引入CoyoteAdapter,这是适配器模式的经典运用,连接器调用 CoyoteAdapter 的 sevice 方法,传入的是 Tomcat Request 对象,CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方 法。
1.Endpoint接收Socket连接,生成一个SocketProcessor任务提交到线程池去处理
2.SocketProcessor的run方法会调用Processor组件去解析应用层协议,Processor通过解析生成Request对象后,会调 用Adapter的service方法。
大家对下面这个结构图不陌生了吧,具体就不单独介绍了
由图中我们可以看到从Bootstrap类的main方法开始, tomcat会以链的方式逐级调用各个模块的init()方法进行初始化, 待各个模块都初始化后, 又会逐级调用各个模块的start()方法启动各个模块. 下面我们通过部分源码看一下这个过程.
关键源码均有注释
public static void main(String[] args) {
synchronized(daemonLock) {
if (daemon == null) {
Bootstrap bootstrap = new Bootstrap();
try {
// 初始化加载器,创建catalia对象(tomcat所有的动作均是由它带头,轰炸机)
bootstrap.init();
} catch (Throwable var5) {
handleThrowable(var5);
var5.printStackTrace();
return;
}
daemon = bootstrap;
} else {
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
}
//主要先执行 load加载,然后 start启动, 这里用的就是模板设计模式启动的
try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
//执行完init()方法后会判断启动参数的值,
// 由于我们采取默认的启动方式, 所以main方法的参数是start, 会进入下面的判断代码块
} else if (command.equals("start")) {
// 让当前主线程阻塞 类似 countdownLatch.await
daemon.setAwait(true);
// 1.加载 各个组件对象
daemon.load(args);
// 2.启动
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null == daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable var7) {
Throwable t = var7;
if (var7 instanceof InvocationTargetException && var7.getCause() != null) {
t = var7.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
可以看到在设置等待后, 调用了本类对象的load()方法. 我们跟进查看load()方法的源码.
load方法注解就是通过 反射执行 catalin 的 load方法
private void load(String[] arguments)
throws Exception {
// Call the load() method
String methodName = "load";
Object param[];
Class<?> paramTypes[];
if (arguments==null || arguments.length==0) {
paramTypes = null;
param = null;
} else {
paramTypes = new Class[1];
paramTypes[0] = arguments.getClass();
param = new Object[1];
param[0] = arguments;
}
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled())
log.debug("Calling startup class " + method);
method.invoke(catalinaDaemon, param);
}
通过跟踪源码我们可以看到catalinaDaemon是Bootstrap类的一个私有成员变量
catalinaDaemor 是在 bootstrap中 init方法初始化完成的,我们可以看看init源码
可以看到init()方法创建了一个Catalina对象, 并把该对象赋给了catalinaDaemon.
public void init()
throws Exception
{
// Set Catalina path
setCatalinaHome();
setCatalinaBase();
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");
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;
}
==然后 catalina 执行 它的 getserver方法 ==
然后我们看 Server对象 的init方法
Server是一个接口,唯一的实现类是StandardServer
由于继承关系先执行 父类的init方法
==在父类方法中调用 initInternal(); == 注意看下面的方法修饰为抽象方法,这就应用了模板设计模式,由子类具体实现逻辑。
执行StandardServer 中的 initInternal方法
protected void initInternal() throws LifecycleException {
super.initInternal();
// Register global String cache
// Note although the cache is global, if there are multiple Servers
// present in the JVM (may happen when embedding) then the same cache
// will be registered under multiple names
onameStringCache = register(new StringCache(), "type=StringCache");
// Register the MBeanFactory
MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
onameMBeanFactory = register(factory, "type=MBeanFactory");
// Register the naming resources
globalNamingResources.init();
// Populate the extension validator with JARs from common and shared
// class loaders
if (getCatalina() != null) {
ClassLoader cl = getCatalina().getParentClassLoader();
// Walk the class loader hierarchy. Stop at the system class loader.
// This will add the shared (if present) and common class loaders
while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
if (cl instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url : urls) {
if (url.getProtocol().equals("file")) {
try {
File f = new File (url.toURI());
if (f.isFile() &&
f.getName().endsWith(".jar")) {
ExtensionValidator.addSystemResource(f);
}
} catch (URISyntaxException e) {
// Ignore
} catch (IOException e) {
// Ignore
}
}
}
}
cl = cl.getParent();
}
}
// 初始化servers中的init方法
for (int i = 0; i < services.length; i++) {
services[i].init();
}
}
==其中 for (int i = 0; i < services.length; i++) {
services[i].init();
} == 是开启子容器的执行, 继续执行 父类 中的init,然后父类中的init调用子类的initInternal 完成初始化
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。