浅析tomcat原理

article/2025/9/14 0:34:46

浅析tomcat原理

上上个星期,看了一下how tomcat works这本书,今天捡起来看一会,发现忘得有点快,特地写点东西,加深一下记忆。因为书讲的是tomcat4,5的内容,比较旧了,所以和最新的tomcat的差距还是有点大的。而且还没看完,以后再补充吧。

而java实现web最简单的方式就是对socket和serversocket的封装。也是早期tomcat的实现方式。

计算机网络之间的通信是基于端口之间通信,对于服务器,从端口读取数据,也就是inputStream, 往端口写数据,也就是outputStream。

serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream();

HttpServletRequest是请求,也就是客户端往服务器端口发送消息,服务器从端口读取数据,所以HttpServletRequest封装了上面的inputStream。 同理HttpServletResponse封装了上面的outputStream。

ServerSocket 监听本机端口, 我们可以去浏览器输入: http://127.0.0.1:8080 然后后台读取程序中读取一个叫做index.html的文件(FileInputStream->bytes),output.write(bytes, 0, lenth). 将文件内容输出到端口,网页中就会显示内容了。是不是有点熟悉。当然tomcat肯定不是这么简单的实现,但是最基本的原理就是如此。

当然这个是静态资源,如果是动态servlet的处理,大致是通过类加载器,加载进内存,反射得到对象。然后根据request请求信息,判断是请求静态文件还是动态servlet,然后执行servlet的service(request, response)方法;

Connector 连接器

直接跳到连接器,有点太快了,书中还有很多小细节,门面设计模式, response中getWriter方法就是封装了outputStream… 推荐去看一下。

连接器,顾名思义,就是用来处理连接的。

 private int port = 8080;private ServerSocket serverSocket = null;

这是我直接在tomcat4源码中HttpConnector拷贝过来的两个参数,然后再来看看这个类的一个重要方法。

public void run() {// Loop until we receive a shutdown commandwhile (!stopped) {Socket socket = null;try {socket = serverSocket.accept();...} catch () {...}HttpProcessor processor = createProcessor();...processor.assign(socket);...}...}

一个循环,等待连接的到来,得到一个socket对象, 然后创建一个处理器,去处理这个socket的请求。然后继续等待下一个连接accept()。

当然如果tomcat这样顺序进行,那肯定是不行的,所以一个连接器有一个processor(处理器)的对象池。而每个处理器实现了runnable接口,在创建的时候就启动了线程,然后阻塞自己,直到自己调用了assign() 方法,就是上面的那个方法,然后执行处理request的方法,处理servlet还是静态资源。完成后继续阻塞自己。

所以tomcat的connector有多个processor,请求来了调用一个processor去执行,而本身不需要等待这个processor完成,继续接收下一个请求。是一种异步实现的感觉。这样可以处理多个请求,而无需阻塞。这也是早期bio的解决方案。现在的解决方案应该是nio了。

final class HttpProcessor implements Lifecycle, Runnable {public void run() {while (!stopped) {Socket socket = await();if (socket == null)continue;try {process(socket);} catch (Throwable t) {log("process.invoke", t);}connector.recycle(this);}synchronized (threadSync) {threadSync.notifyAll();}}
}

就是在await()方法阻塞,然后释放,执行process完成,循环继续阻塞。

processor 处理器

首先看看这个processor做了什么吧。

  • 创建HttpServletRequest, HttpServletResponse对象。
  • 解析连接
  • 解析请求
  • 解析头部, 给request.setHeader。
  • 隐式调用了servlet的service方法。 虽然从这里开始,但并不是直接调用。

具体是怎么解析的请求,我没有深入去了解,大概就是拆分字符串,截取之类的吧,还是看看这个类最重要的方法。process() 方法。

   private void process(Socket socket) {...try {input = new SocketInputStream(socket.getInputStream(),connector.getBufferSize());} catch (Exception e) {...}keepAlive = true;while (!stopped && ok && keepAlive) {finishResponse = true;try {request.setStream(input);request.setResponse(response);output = socket.getOutputStream();response.setStream(output);response.setRequest(request);((HttpServletResponse) response.getResponse()).setHeader("Server", SERVER_INFO);} catch (Exception e) {...}...//这里解析请求,给丰富request和response。try {...if (ok) {// 重点。 画上!!!connector.getContainer().invoke(request, response);}} catch (ServletException e) {...}}

大致就是上面,可以看出,request和response封装了输入输出流,然后解析请求, 调用了container的invoke(request, response)方法。所以我们希望见到的service方法就藏在这里面了。

Container 容器

这个可以说是tomat中最被人熟知的东西之一。tomcat4中有四大容器,以我的理解简单介绍一下, 可能有点不对。

  • Engine 引擎, 启动一个tomcat服务,也就是启动一个引擎
  • host 虚拟主机, 一个Engine启动,下面项目都会启动,localhost:8080/work1,work2
  • context 上下文, 一个项目对应一个上下文,通过map映射到不同的servlet。
  • wrapper 包装器, 一个wrapper对应一个servlet。

上面的四个都实现了Container接口,就先来谈谈wrapper吧。connector中有个方法,setContainer(Container container); 如果一个wrapper被一个connector绑定,那么回到上面画重点的方法。

connector.getContainer().invoke(request, response);

wrapper 包装器

所以点进wrapper类中找寻这个方法,发现没有,这个方法的实现在他的父类ContainerBase中有实现。

  public void invoke(Request request, Response response) throws IOException, ServletException {pipeline.invoke(request, response);}

出现了一个新的东西,叫做管道(pipeline)。点下去,会发现很麻烦,先来捋一捋Container中这些的关系。

pic

container 中包含了一个pipeline, 而pipeline执行invoke方法是创建了一个pipelineContext对象,并执行invokeNext方法。 然后pipelineContext对象就会去执行Valve的invoke方法。当然,执行方式有点像递归,一直往下,直到执行basicvalve的invoke方法,这个方法中会隐式执行service方法,然后再回去执行上一个valve。看看basicvalve的invoke方法。

public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException {...StandardWrapper wrapper = (StandardWrapper) getContainer();ServletRequest sreq = request.getRequest();ServletResponse sres = response.getResponse();Servlet servlet = null;HttpServletRequest hreq = null;if (sreq instanceof HttpServletRequest)hreq = (HttpServletRequest) sreq;HttpServletResponse hres = null;if (sres instanceof HttpServletResponse)hres = (HttpServletResponse) sres;...try {if (!unavailable) {// 划重点。。。servlet = wrapper.allocate();}} catch (ServletException e) {...}ApplicationFilterChain filterChain = createFilterChain(request, servlet);try {...if ((servlet != null) && (filterChain != null)) {// 划重点2。。。filterChain.doFilter(sreq, sres);}...}}

通过getContainer得到wrapper, wrapper.allocate(). 这个方法中通过反射之类的得到了servlet对象,返回。然后创建一个过滤器链, 调用doFilter方法传递request和response。我们再看看doFilter方法。

  if ((request instanceof HttpServletRequest) &&(response instanceof HttpServletResponse)) {servlet.service((HttpServletRequest) request, (HttpServletResponse) response);} else {servlet.service(request, response);}

这个方法中,终于找到了调用service方法了。当然上面说的都是wrapper。一个wrapper只对应一个servlet,但是一个项目肯定有多个servlet,那么这就涉及到我们熟悉的Context(上下文)了。

context 上下文

我们再回到connector,connector.setContainer(context). 如果connector设置的容器是上下文。再来分析一下。想起我们之前的那个方法。

connector.getContainer().invoke(request, response);

context的invoke和wrapper一样,pipeline.invoke, 然后同样是pipelineContext.invokeNext。 那么不一样的地方在哪里呢? 那就是basicvalve, 我们称为contextValve。 我们看看contextValve的invoke方法。

public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException {...Context context = (Context) getContainer();Wrapper wrapper = null;try {wrapper = (Wrapper) context.map(request, true);} catch (IllegalArgumentException e) {badRequest(requestURI, (HttpServletResponse) response.getResponse());return;}if (wrapper == null) {notFound((HttpServletResponse) response.getResponse());return;}response.setContext(context);wrapper.invoke(request, response);}

相当简洁, 就是context从request中读取到类似 /IndexServlet, 然后就会去map中搜索,找到处理这个IndexServlet的servlet。也就是wrapper,执行wrapper的invoke,又回到了上面wrapper的方法,记得上面的说的吗,一个wrapper只处理一个servlet。而一个上下文对应多个servlet。 而这里的map就是我们经常写的xml映射关系。

  <servlet-mapping>  <servlet-name>IndexServlet</servlet-name>  <url-pattern>/IndexServlet</url-pattern>  </servlet-mapping>  

当然这个map有一个专门的类ContextMapper, 这个就不深究如何映射的。还有上面类加载,反射servlet的方法,其实也有一个专门的接口叫Loader。我也没看太懂。

然后至于host和engine的实现,没看完,看看以后看完了有时间再来补上。原理应该差不多。


http://chatgpt.dhexx.cn/article/CisPDdf2.shtml

相关文章

Tomcat底层原理

一、Tomcat启动时到底对我们的应用程序做了什么&#xff1f; 当我们把一个应用程序的war包放到Tomcat的webapps目录后&#xff0c;启动Tomcat&#xff0c;然后就可以通过浏览器发送Http请求访问该war包内的Servlet了。 这个过程包括&#xff1a; 1、启动Tomcat 2、Tomcat处理H…

tomcat的工作原理以及简介

Tomcat简介 Tomcat是一个JSP/Servlet容器。其作为Servlet容器&#xff0c;有三种工作模式&#xff1a;独立的Servlet容器、进程内的Servlet容器和进程外的Servlet容器&#xff0c; 1.Tomcat是运行在JVM中的一个进程。它定义为【中间件】&#xff0c;顾名思义&#xff0c;是一个…

tomcat组成及工作原理

1 - Tomcat Server的组成部分 1.1 - Server A Server element represents the entire Catalina servlet container. (Singleton) 1.2 - Service A Service element represents the combination of one or more Connector components that share a single Engine Servic…

Tomcat工作原理介绍

Web应用程序都是靠Web服务器运行的&#xff0c;Tomcat是常用的Web服务器(兼具Servlet容器HTTP服务器功能)之一&#xff0c;此篇博客将从工作原理上来认识Tomcat。Tomcat作为Web服务器需要处理两类核心任务&#xff1a;处理 Socket 连接&#xff0c;负责网络字节流与Request和Re…

tomcat原理解析(一):一个简单的实现

一 概述 前段时间去面试&#xff0c;被人问到了tomcat实现原理。由于平时没怎么关注容器的实现细节&#xff0c;这个问题基本没回答上来。所以最近花了很多时间一直在网上找资料和看tomcat的源码来研究里面处理一个HTTP请求的流程。网上讲tomcat的帖子比较多&#xff0c;大多都…

Tomcat工作原理之运行机制

一、Tomcat运行原理分析1.Tomcat是运行在JVM中的一个进程。它定义为【中间件】&#xff0c;顾名思义&#xff0c;是一个在Java项目与JVM之间的中间容器。 2.Web项目的本质&#xff0c;是一大堆的资源文件和方法。Web项目没有入口方法(main方法)&#xff0c;&#xff0c;意味着…

tomcat 工作原理

大致的架构是 jsptomcatmysql&#xff0c;记录tomcat学习一点笔记。 Tomcat是Servlet运行环境&#xff08;容器&#xff09;&#xff0c;每个servlet执行init(),service(),destory() 以下是servlet的作用 Servlet的调用 Tomcat的工作模式3种&#xff1a;独立Servlet&#xff0c…

Tomcat的原理及架构

转自&#xff1a;https://zhuanlan.zhihu.com/p/35398064 俗话说&#xff0c;站在巨人的肩膀上看世界&#xff0c;一般学习的时候也是先总览一下整体&#xff0c;然后逐个部分个个击破&#xff0c;最后形成思路&#xff0c;了解具体细节&#xff0c;Tomcat的结构很复杂&#xf…

Tomcat基本原理

1.Tomcat核心&#xff1a; Http服务器Servlet容器 组件分工&#xff1a; 连接器Connector&#xff1a;处理 Socket 连接&#xff0c;负责网络字节流与 Request 和 Response 对象的转化。容器Container&#xff1a;加载和管理 Servlet&#xff0c;以及具体处理 Request 请求。 …

tomcat的工作原理

本文源自转载&#xff1a;你还记得 Tomcat 的工作原理么 一、Tomcat 整体架构 Tomcat 是一个免费的、开源的、轻量级的 Web 应用服务器。适合在并发量不是很高的中小企业项目中使用。 二、文件目录结构 以下是 Tomcat 8 主要目录结构 三、功能组件结构 Tomcat 的核心功能有…

Tomcat原理整理

目录接口 功能组件 Tomcat 的核心功能有两个&#xff0c;分别是负责接收和反馈外部请求的连接器 Connector&#xff0c;和负责处理请求的容器 Container。其中连接器和容器相辅相成&#xff0c;多个 Connector 和一个 Container 一起构成了基本的 web 服务 Service。每个 Serve…

Tomcat工作原理详细介绍

大部分企业的 Web 应用都运行在它上面&#xff0c;Tomcat 对于程序员来说算是老朋友了&#xff0c;那么今天带大家走近这位老朋友&#xff0c;看看它是如何处理 Web 请求&#xff0c;以及它内部的体系结构&#xff0c;这对帮助我们理解 Tomcat 的使用大有益处。 本文你将会学会…

Tomcat原理

Tomcat顶层架构 Tomcat的顶层结构图&#xff1a; 1、Tomcat中最顶层的容器是Server&#xff0c;代表着整个服务器&#xff0c;一个Server可以包含至少一个Service&#xff0c;用于具体提供服务。 2、Service主要包含两个部分&#xff1a;Connector和Container。 Tomcat 的心脏…

javascript 文本框限制输入1到10位数字正则表达式

<meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <!DOCTYPE html> <html> <head><title>DOM 教程</title><style></style><!--不需要再次引用jquery--><script type"te…

js数字正则

js正则表达式 1.了解什么是正则表达式&#xff1f; 正则表达式&#xff08;Regular Expression&#xff09;又称规则表达式&#xff0c;简单来说它就是一个概念&#xff0c;用事先声明好的字符和字符的组合&#xff0c;来组成一个“规则字符串”&#xff0c;用来检测我们书写…

卷积神经网络降维方法,深度神经网络降维方法

1、卷积神经网络中用1*1 卷积有什么作用或者好处 1*1卷积的主要作用有以下几点&#xff1a; 1、降维&#xff08; dimension reductionality &#xff09;。比如&#xff0c;一张500 * 500且厚度depth为100 的图片在20个filter上做1*1的卷积&#xff0c;那么结果的大小为500*5…

常用降维方法

降维方法分为线性核非线性降维&#xff0c;非线性降维又分为基于核函数和基于特征值的方法。 线性降维方法&#xff1a;PCA ICA LDA LFA LPP(LE的线性表示) 基于核函数的非线性降维方法&#xff1a;KPCA KICA KDA 基于特征值的非线性降维方法&#xff08;流型学习&#x…

机器学习四大数据降维方法详解

引言&#xff1a; 机器学习领域中所谓的降维就是指采用某种映射方法&#xff0c;将原高维空间中的数据点映射到低维度的空间中。降维的本质是学习一个映射函数 f : x->y&#xff0c;其中x是原始数据点的表达&#xff0c;目前最多使用向量表达形式。 y是数据点映射后的低维向…

机器学习 | 降维问题

目录 一、主成分分析 二、奇异值分解 2.1 奇异值分解原理 2.2 奇异值分解实践 三、特征值与特征向量 一、主成分分析 主成分有如下特征&#xff1a; 每个主成分是原变量的线性组合&#xff1b;各个主成分之间互不相关&#xff1b;主成分按照方差贡献率从大到小依次排列&…

数据降维方法总结

Introduce 经过这几天面试后&#xff0c;我发现数据降维这一块在工业界用的很多或者说必不可少&#xff0c;因此&#xff0c;这方面需要重点关注。今天&#xff0c;我将数据降维总结于此&#xff0c;包括他人成果&#xff0c;这里对他们的内容表示感谢。 Method 对数据降维作…