一,Tomcat介绍
1,Tomcat官网:https://tomcat.apache.org
The Apache Tomcat® software is an open source implementation of the Java Servlet, JavaServer Pages, Java Expression Language and Java WebSocket technologies.
Tomcat可以称为Web容器或Servlet容器。
2,怎么让Tomcat具有Servlet容器的功能呢?
tomcat的lib包中有servlet-api.jar包,对servlet规范进行了了实现。进而封装一个个的Servlet,实现方式如下:
public interface Servlet {
void init(ServletConfig config) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
String getServletInfo(); void destroy();
}
自定义servlet举例:
class LoginServlet extends HttpServlet{
doGet(request,response){};
doPost(request,response){};
}
web.xml中的配置
LoginServlet
com.xxx.web.servlet.LoginServlet
LoginServlet
/login
3,Tomcat的代码原理:
class MyTomcat{
List list=new ArrayList();
//监听端口
ServerSocket server=new ServerSocket(8080);
//接收请求
Socket socket=server.accept();
// 把请求和响应都封装在业务代码中的servlet
// 只要把业务代码中一个个servlets添加到tomcat中即可
list.add(servlets);
}
二,Tomcat源码
1,源码下载:https://archive.apache.org/dist/tomcat/tomcat-8/v8.0.11/src/
2,产品目录文件含义
- bin:主要用来存放命令,.bat是windows下,.sh是Linux下
- conf:用来存放tomcat的一些配置文件
- lib:存放tomcat依赖的一些jar包
- log:存放tomcat在运行时产生的日志文件
- temp:存放运行时产生的临时文件
- webapps:存放应用程序
- work:存放tomcat运行时编译后的文件,比如JSP编译后的文件
3,源码导入与调试
(1) 根据上面的链接下载对应的tomcat源码
(2) 创建pom.xml文件
4.0.0
org.apache.tomcat
Tomcat8.0
Tomcat8.0
8.0
Tomcat8.0
java
test
java
test
org.apache.maven.plugins
maven-compiler-plugin
2.3
UTF-8
1.8
junit
junit
4.12
test
org.easymock
easymock
3.4
ant
ant
1.7.0
wsdl4j
wsdl4j
1.6.2
javax.xml
jaxrpc
1.1
org.eclipse.jdt.core.compiler
ecj
4.5.1
(3) 将源码导入到idea中
(4) 创建application,并填写name, Main class,VM options信息:
(5) 在当前源码目录创建apache-tomcat-8.0.11文件夹,并将一些文件拷贝到该目录下,如bin、conf、lib、logs、temp、webapps、work
(6) 启动,发现报错,找不到CookieFileter,直接删除
(7) 打开浏览器访问:localhost:8080
4,web端口监听验证
org.apache.catalina.connector.Connector#initInternal()--- org.apache.coyote.ProtocolHandler#init---org.apache.coyote.AbstractProtocol#init---org.apache.tomcat.util.net.AbstractEndpoint#init
--- org.apache.tomcat.util.net.JIoEndpoint#bind
--- org.apache.tomcat.util.net.DefaultServerSocketFactory#createSocket(int)
@Override
public ServerSocket createSocket (int port, int backlog)
throws IOException {
//Java IO | Socket
return new ServerSocket (port, backlog);
}
5,servlets容器验证
Context标签就是代表一个web项目。http://tomcat.apache.org/tomcat-8.0-doc/architecture/overview.html
A Context represents a web application.
所以web项目的加载是从Context开始的。
org.apache.catalina.core.StandardContext#loadOnStartup
读取配置:org.apache.catalina.startup.ContextConfig#configureContext
for (ServletDef servlet : webxml.getServlets().values()) {
Wrapper wrapper = context.createWrapper();
// Description is ignored
// Display name is ignored
// Icons are ignored
if (servlet.getLoadOnStartup() != null) {
wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());
}
.....
context.addChild(wrapper);
}
读取web.xml:
org.apache.catalina.startup.ContextConfig#createWebXml
private static final StringManager sm =
StringManager.getManager(Constants.PACKAGE_NAME);
public class Constants {
public static final String PACKAGE_NAME =
Constants.class.getPackage().getName();
public static final String WEB_XML_LOCATION = "/WEB-INF/web.xml";
}
三,Tomcat架构分析
1,tomcat核心架构图:
架构图----源码----server.xml 一一对应的关系:
http://tomcat.apache.org/tomcat-8.0-doc/architecture/overview.html
- Server:代表整个容器
- Service:是一个中间的桥梁,用于连接server和一个或多个Connector。
- Connector:处理和客户端交互的请求。
- Executor:代表一个线程池
- Engine:作为pipeline,管理多个虚拟主机
- Host:代表一个域名,可以支持多个虚拟主机。
- Cluster:用于管理集群
- Manager:用于管理session。
Tomcat两个核心组件:
对外:Connector
对内:Containner,源码中的关系:Container--Engine--Host--Context--Wrapper
SpringBoot内置的tomcat:
也有Connector,去掉了JIO的绑定。内置tomcat的源码和tomcat的架构基本一致。
2,Connector:
(1),EndPoint:监听通信端口,是对传输层的抽象,用来实现TCP/IP协议的。
对应的抽象类为AbstractEndPoint,有很多实现类,如NioEndPoint,JIoEndPoint。在其中有2个组件,一个是Acceptor,另一个是SocketProcessor。
Acceptor用来监听Socket连接请求,SocketProcessor用来处理接收到的Socket请求。
- BIO/JIO:同步阻塞的IO,针对并发量较大的时候,效率很低,一个连接一个线程
- NIO:同步非阻塞IO,并发量比较大的时候,比较占优势,单独一个线程,处理并发
- Apr:与本地方法库进行交互
Tomcat8默认使用NIO的方式,Tomcat默认使用BIO的方式。
org.apache.catalina.connector.Connector#setProtocol
public void setProtocol(String protocol) {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName ("org.apache.coyote.http11.Http11NioProtocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
}
}
(2),Processor:Processor是用于实现HTTP协议的,也就是说Processor是针对应用层协议的抽象。Processor接受来自EndPoint的Socket,然后解析成Tomcat Request和Tomcat Response对象,最后通过Adapter提交给容器。
对应的抽象类为AbstractProcessor,有很多实现类,比如AjpProcessor、Http11Processor等。
(3),Adapter:ProtocolHandeler接口负责解析请求并生成Tomcat Request类。需要把这个Requert对象转换成ServletRequest。 Tomcat引入CoyoteAdapert,这是适配器模式的应用,连接器调用CoyoteAdapter的service方法,传入的是Tomcat Request对象,CoyoteAdapert负责将Tomcat Request转成ServletRequest,再调用容器的service方法。
3,request请求
UML图:http://tomcat.apache.org/tomcat-8.0-doc/architecture/requestProcess/request-process.png
四,Tomcat启动流程
1,BootStrap:
BootStrap是Tomcat的入口类:org.apache.catalina.startup.Bootstrap#main
//bootstrap.inin()
initClassLoaders(); //初始化自定义的类加载器
Thread.currentThread().setContextClassLoader(catalinaLoader); //启动线程
SecurityClassLoad.securityClassLoad(catalinaLoader); //安全相关
//初始化组件,并进行协同工作
daemon.load(args);
daemon.start();
2,Catalina:
解析server.xml文件
创建server组件,并且调用其init和start方法
3,Lifecycle:
用于管理各组件的生命周期,包含init、start、stop、destroy方法
LifecycleBase实现了Lifecycle,利用的是模板设计模式
4,Server:
管理Service组件,并用调用其init和start方法
5,Service:
管理连接器和Engine
启动全流程:http://tomcat.apache.org/tomcat-8.0-doc/architecture/startup.html
启动流程的UML:http://tomcat.apache.org/tomcat-8.0-doc/architecture/startup/serverStartup.pdf