Tomcat服务器结构浅析(一)
最近有点懒,博客更新少,补上一篇之前的欠债。。。这篇博客内容基于《Tomcat架构解析》,这里把Tomcat主要的结构介绍了下,更详细的内容大家可以参考该书。 Tomcat是全世界最著名的基于Java语言的轻量级应用服务器,是一款完全开源免费的Servlet容器实现。同时,它支持HTML,JS等静态资源的处理,因此也可作为轻量级的WEB服务器来使用。在以前的WEB开发当中,我们主要通过将..
最近有点懒,博客更新少,补上一篇之前的欠债。。。这篇博客内容基于《Tomcat架构解析》,这里把Tomcat主要的结构介绍了下,更详细的内容大家可以参考该书。
Tomcat是全世界最著名的基于Java语言的轻量级应用服务器,是一款完全开源免费的Servlet容器实现。同时,它支持HTML,JS等静态资源的处理,因此也可作为轻量级的WEB服务器来使用。在以前的WEB开发当中,我们主要通过将程序打包,将打包文件放到webapps下来进行访问,而在使用SpringBoot作为开发框架的情况下,由于SpringBoot已内嵌Tomcat,不需要将打包文件放在特定的文件夹下,而是直接运行程序即可。这篇博客第一部分内容将介绍Tomcat的整体架构,第二部分介绍SpringBoot内嵌Tomcat的实现。
Tomcat总体架构
首先,让我们来看一张图:
Tomcat总体的设计便是围绕着这张图来的。下面我们依次对上图中的各个部分做一下介绍。
Lifecycle 接口
该接口主要定义了容器整个生命周期过程中的各个阶段
public interface Lifecycle {
public void init() throws LifecycleException;
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void destroy() throws LifecycleException;
public void addLifecycleListener(LifecycleListener listener);
...
}
该接口包含了容器初始化,开始,停止,销毁等过程。其实现类的各个组件在容器的工作过程当中需要做的工作,即在这几个函数中来完成。
Server
表示整个Servlet容器,因此Tomcat运行环境中只有唯一一个Server实例。在该接口的唯一实现类StandardServer中,除了表示Service的一个对象数组外,主要是一些关于Tomcat的属性,比如port,address等。该容器的这些属性,可以通过properties文件或者yaml文件进行配置(比如端口通过server.port=8080进行配置),或者是原来的开发方式,通过Server.xml进行配置。
Service
Service表示一个或者多个Connector的集合,这些Connector共享同一个Container(即Engine)来处理其请求。在同一个Tomcat实例内可以包含任意多个Service实例,它们彼此独立。Service其实是作为Tomcat中接收请求,以及处理请求的容器的纽带存在的。tomcat中的实现类StandardService有以下几个重要的属性:
public class StandardService extends LifecycleMBeanBase implements Service {
private Server server = null;
protected Connector connectors[] = new Connector[0];
private Engine engine = null;
protected final Mapper mapper = new Mapper();
}
server表示其所属Server,Engine作为处理该service中Connector的容器。Mapper可以看作是映射器,要来处理请求地址到处理该请求的容器及Servlet的映射。
Engine
在Tomcat中,Engine为最高层级的容器对象。尽管Engine不是直接处理请求的容器,却是获取目标容器的入口。
Host
Host 作为一类容器,表示Servlet引擎(Engine) 中的虚拟机, 与一个服务器的网络名有关,如域名等。客户端可以使用这个网络名连接服务器,这个名称必须要在DNS服务器上注册
Context
Context作为一类容器,用于表示ServetContext ,在Servlet规范中, 一个ServletContext表示一个独立的Web应用
Wrapper
Wrapper作为一类容器, 用于表示Web应用中定义的Servlet(其实是对Servlet进行了一层封装)。
Connector
表示Tomcat中的链接器,其主要作用是监听并转化Socket请求,并交由Container处理。其实就是对不同协议及协议处理器进行的封装。下面是我们需要关注的几个属性域:
public class Connector extends LifecycleMBeanBase {
protected Service service = null;
protected final ProtocolHandler protocolHandler;
}
Service是其父容器,ProtocolHandler表示协议处理器
ProtocolHandler
ProtocolHandler表示协议处理器,是一个接口,其实现类有以下几种:
从图中我们大概能够猜到,其中的每一个实现类,其实都代表着一种I/O协议的处理过程,我们以同步非阻塞I/O的处理器Http11NioProtocol为例,其最初继承于抽象类AbstractProtocol,它的定义如下:
public abstract class AbstractProtocol<S> implements ProtocolHandler,
MBeanRegistration {
private final AbstractEndpoint<S> endpoint;
private Handler<S> handler;
private final Set<Processor> waitingProcessors = Collections.newSetFromMap(new ConcurrentHashMap<Processor, Boolean>());
}
AbstractEndpoint代表的是协议端点,比如,Nio使用的是NioEndpoint类,即为nio的实现逻辑,对nio类型的Socket进行监听, Handler作为AbstractEndpoint接收到I/O后,用来处理I/O的处理器。
请求处理过程
当我们的浏览器或者是其他工具发起一个Http请求时候,Tomcat的整个处理过程如下:
从一开始的Endpoint监听到Http请求后,调用Processor进行处理,Process调用CoyoteAdapter进行处理,CoyoteAdapter通过Mapper获取到处理该请求的顶级容器Engine,通过一层层的查找,最终获取到处理该请求的Wrapper,经过Tomcat中定义的一系列过滤器(Filter)后,最终由Servlet(在SpringMVC中,便是被DispatcherServlet)进行了消费。Tomcat整个处理的流程便是这样的。
SpringBoot内嵌Tomcat
再完成了Tomcat简单的解析之后,我们还要问,在启动SpringBoot应用的过程当中,是如何启动Tomcat的呢?在Tomcat中,其已经为我们提供了一个表示其实例的Tomcat类,通过查找,我们知道,该类的实例是在TomcatEmbeddedServletContainerFactory类的getEmbeddedServletContainer函数中被创建的。启动一个简单的SpringBoot应用,通过断点,我们能够看到它被调用的路径:
从上图可知,到Springboot应用刷新容器的时候,会在该过程当中创建Tomcat的实例,我们来下看下函数的实现过程:
public class TomcatEmbeddedServletContainerFactory
extends AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
// 创建Tomcat的实例
Tomcat tomcat = new Tomcat();
// 为Tomcat设置应用的根目录
File baseDir = (this.baseDirectory != null ? this.baseDirectory
: createTempDir("tomcat"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 根据Springboot使用的I/O协议,创建Connector,默认的协议是`String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol`,及NIO协议(同步非常阻塞)
Connector connector = new Connector(this.protocol);
// 为Service添加Connector,若Tomcat还没有Service,则getService函数中会创建
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
// 通过配置autoDeploy禁止虚拟主机自动部署Web应用
tomcat.getHost().setAutoDeploy(false);
// 配置Tomcat的顶级容器Engine
configureEngine(tomcat.getEngine());
// 添加额外的自定义协议的Connector
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
// 配置虚拟主机Host,其内会进一步初始化Host的字容器
prepareContext(tomcat.getHost(), initializers);
// 对Tomcat进行包装,返回TomcatEmbeddedServletContainer的实例
return getTomcatEmbeddedServletContainer(tomcat);
}
}
关于Tomcat的内容其实还有很多,只是由于时间限制,不能在这里更深入地讲解,若后期有机会,会继续更加深入地介绍Tomcat的各个组件,这篇内容就做为Tomcat容器系列的第一篇吧~
欢迎关注个人公众号:
更多推荐
所有评论(0)