Tomcat架构浅析
基本架构如图所示,咱们主要把关注点放在Connector
和Container
这两个组件这里。
Connector
组件 ,相当于tomcat的外交大臣,把浏览器传来的字节流封装处理成ServletRequest
对象,之后再把ServletRequest
对象 转发给Contaniner
组件处理。当Container
组件处理完毕之后,Contaniner
组件会给Connector
组件返回一个 ServletResponse
对象,该对象再反过来经由Connector
组件一系列处理,还原成字节流,最终把返回结果转发给浏览器,让浏览器进行页面渲染。
过程挺简单的,但显然不是今天的重点,我们内存马主要还是依靠这里的Container
组件来实现的,所以我们再跟进分析一下Container
组件的运行机制,大体如下图所示。
(Container
组件又称 Catalina
,下文存在一定的混用,别混淆了)
这里面从Engine到Wrapper涉及到了几个细分概念,我们先不急着解释,可以先从我下面偷的
这张图来感受一下他们之间的层次关系。
能够看出来层次关系大致是遵循树形结构的(wrapper和servlet肯定不是,人家就是一对一的),从这张图的边角注释基本也能猜出来,各个容器的职能,但还是来做一下具体解释。
- Engine:表示整个 Catalina 的 Servlet 引擎,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine,但是一个引擎可包含多个 Host
- Host:代表一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可包含多个 Context
- Context:表示一个 Web 应用程序,每一个Context都有唯一的path,一个Web应用可包含多个 Wrapper
- Wrapper:表示一个Servlet,负责管理整个 Servlet 的生命周期,包括装载、初始化、资源回收等
以上就是关于Connector组件中子容器的介绍,但我们重新回到那个图里面,我们仍然可以发现子容器之中亦有迷雾尚未解开,就比如每个容器都出现的那个 Pipeline
我们就不清楚它到底是什么东西。这里就要再介绍一下Tomcat 的 阀和管道 机制。
首先什么是管道?我们可以先看一下接口的定义
1 | public interface Pipeline extends Contained { |
可以看出来,阀是由管道所调度掌控的,一个管道可以拥有多个阀,但管道并不直接实现功能,而是由阀所掌控的阀来实现具体功能(就是Valve#invoke)这里来实现。他们的运行机制有点类似于FilterChain那种责任链机制,层层外包,通力协作,当一个管道所有的阀的被调度完成,则最后一个阀可以调度别的管道的首阀开始新一轮的外包协作。
(这个图略了点,只有一个管道,稍微抽象点,但毕竟图是偷的,凑合着看吧)
Tomcat中三个Context
ServletContext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55package javax.servlet;
...
public interface ServletContext {
String TEMPDIR = "javax.servlet.context.tempdir";
String ORDERED_LIBS = "javax.servlet.context.orderedLibs";
String getContextPath();
ServletContext getContext(String var1);
Servlet getServlet(String var1) throws ServletException;
Enumeration<Servlet> getServlets();
Enumeration<String> getServletNames();
void log(String var1);
void log(Exception var1, String var2);
void log(String var1, Throwable var2);
String getRealPath(String var1);
String getServerInfo();
String getInitParameter(String var1);
Enumeration<String> getInitParameterNames();
boolean setInitParameter(String var1, String var2);
Object getAttribute(String var1);
Enumeration<String> getAttributeNames();
void setAttribute(String var1, Object var2);
void removeAttribute(String var1);
String getServletContextName();
Dynamic addServlet(String var1, String var2);
Dynamic addServlet(String var1, Servlet var2);
Dynamic addServlet(String var1, Class<? extends Servlet> var2);
Dynamic addJspFile(String var1, String var2);
<T extends Servlet> T createServlet(Class<T> var1) throws ServletException;
ServletRegistration getServletRegistration(String var1);
Map<String, ? extends ServletRegistration> getServletRegistrations();
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, String var2);
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Filter var2);
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Class<? extends Filter> var2);
<T extends Filter> T createFilter(Class<T> var1) throws ServletException;
FilterRegistration getFilterRegistration(String var1);
Map<String, ? extends FilterRegistration> getFilterRegistrations();
SessionCookieConfig getSessionCookieConfig();
void setSessionTrackingModes(Set<SessionTrackingMode> var1);
Set<SessionTrackingMode> getDefaultSessionTrackingModes();
Set<SessionTrackingMode> getEffectiveSessionTrackingModes();
void addListener(String var1);
<T extends EventListener> void addListener(T var1);
void addListener(Class<? extends EventListener> var1);
<T extends EventListener> T createListener(Class<T> var1) throws ServletException;
JspConfigDescriptor getJspConfigDescriptor();
ClassLoader getClassLoader();
void declareRoles(String... var1);
String getVirtualServerName();
int getSessionTimeout();
void setSessionTimeout(int var1);
String getRequestCharacterEncoding();
void setRequestCharacterEncoding(String var1);
String getResponseCharacterEncoding();
void setResponseCharacterEncoding(String var1);
}当我们使用Tomcat这样的Java Web服务器时,它提供了一个特殊的对象叫做ServletContext(Servlet上下文)。可以把ServletContext看作是一个容器,它存储了与Web应用程序相关的信息和功能。通俗来说,ServletContext就像是整个Web应用程序的大本营。它保存了所有在同一个Web应用程序中运行的Servlet共享的数据、配置和资源。可以把它看作是一个大家庭的家长,负责协调和管理每个Servlet的需求,并提供它们需要的支持。我们所有的Servlet都得对其进行实现。
ApplicationContext
在Tomcat中,ServletContext接口的具体实现就是ApplicationContext类,其实现了ServletContext接口中定义的一些方法。StandardContext
org.apache.catalina.core.StandardContext
是子容器Context
的标准实现类,其中包含了对Context子容器中资源的各种操作。也是我们内存马这里真正起到作用的类。
总结以下大致如下
引用下别的师傅的话
1 | ServletContext接口的实现类为ApplicationContext类和ApplicationContextFacade类,其中ApplicationContextFacade是对ApplicationContext类的包装。我们对Context容器中各种资源进行操作时,最终调用的还是StandardContext中的方法,因此StandardContext是Tomcat中负责与底层交互的Context。 |
三大组件加载顺序
三者的加载顺序为Listener->Filter->Servlet
1 | if (ok) { |