# minicat
**Repository Path**: nicholas_lcj/minicat
## Basic Information
- **Project Name**: minicat
- **Description**: 作业⼀(编程题):
开发Minicat V4.0,在已有Minicat基础上进⼀步扩展,模拟出webapps部署效果磁盘上放置⼀个webapps⽬录,webapps中可以有多个项⽬,⽐如demo1,demo2,demo3...具体的项⽬⽐如demo1中有serlvet(也即为:
servlet是属于具体某⼀个项⽬的servlet),这样的话在Minicat初始化配置加载,以及根据请求url查找对应
serlvet时都需要进⼀步处理!!!重要
备注:
读取项目磁盘统一路径:
appBase="/Users/webapps",并且提交自己的webapps以及访问路径
作业⼆(简答题):
请详细描述
Tomcat
体系结构(图⽂并茂)
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2020-04-27
- **Last Updated**: 2021-11-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# minicat
#### 一、介绍
作业⼀(编程题):
开发Minicat V4.0,在已有Minicat基础上进⼀步扩展,模拟出webapps部署效果磁盘上放置⼀个webapps⽬录,webapps中可以有多个项⽬,⽐如demo1,demo2,demo3...具体的项⽬⽐如demo1中有serlvet(也即为:
servlet是属于具体某⼀个项⽬的servlet),这样的话在Minicat初始化配置加载,以及根据请求url查找对应
serlvet时都需要进⼀步处理!!!重要
备注:
读取项目磁盘统一路径:
appBase="/Users/webapps",并且提交自己的webapps以及访问路径
作业⼆(简答题):
请详细描述Tomcat体系结构(图⽂并茂)
**视频讲解地址:https://www.bilibili.com/video/BV1SK4y1b7jt/**
#### 二、开发Minicat4.0
##### 2.1、目录结构
minicat(主目录)
|-----------demo1 编译webapps中demo1中的Servlet类。
|-----------demo2 编译webapps中demo2中的Servlet类。
|-----------minicat minicat的主目录
|-----------webapps minicat启动时加载的webapp
|-----------README.md 作业说明
##### 2.2、Minicat包结构说明
minicat
|------src 源码目录
| |--------java
| |---------com.lagou.edu.minicat minicat顶层包
| |--------- adapter 适配器
| |--------- classloader 自定义Web类加载器
| |--------- connector 连接器组件
| |--------- container 容器组件
| |--------- life 生命周期接口
| |--------- process 连接器处理器
##### 2.3、容器组件开发
###### 2.3.1、LifeCycle接口以及LifeCycleBase抽象类
LifeCycle接口以及LifeCycleBase抽象类定义在life生命周期接口包下,提供初始化流程规范。
LifeCycle定义生命周期范围,这里只定义了初始化init接口和start启动接口。
LifeCycleBase是个抽象类,实现了LifeCycle接口,并且提供各容器做具体实现的initInternal和startInternal模板接口。
###### 2.3.2、Server容器接口以及Server容器实现StandServer
Server容器定义了容器的主要业务规范,包含:
- setServices 设置Services子容器。
- findServices 查找Service子容器。
- addConnector 添加Connector连接器。
- getExecutor 获取线程池对象,这里将线程池在Server中进行初始化,因此,需要将线程池通过该方法获取。
StandServer容器实现了Server容器接口,并且继承LifeCycleBase接口类。
- initInternal 初始化接口具体实现,主要步骤:
- 调用循环service子容器的初始化;
- 循环调用Connector的初始化;
- 初始化线程池
- startInternal 启动接口具体实现,主要步骤:
- 循环调用service子容器的启动start接口;
- 循环调用Connector连接器的启动start接口;
###### 2.3.3、Service容器接口以及Service容器实现StandService
Service容器主要维护父容器Server和子容器Engines的关系,并定义了业务规范,包含:
- setServer 设置Server容器;
- addEngine 添加Engine容器;
- getEngines 获取Engine容器集合;
StandService容器实现了Service容器,并继承LifeCycleBase接口类。
- initInternal 循环调用Engine子容器的初始化接口;
- startInternal 循环调用Engine子容器的start启动接口;
###### 2.3.4、Engine容器接口以及Engine容器的实现StandEngine
Engine容器主要定义设置父容Service和Host虚拟主机子容器的关系的业务规范,包含:
- setService 设置父容器service
- getService 获取父容器service
- setHosts 设置虚拟主机容器Host
- getHosts 获取所有虚拟主机容器
StandEngine容器实现了Engine容器,并继承LifeCycleBase接口类。
- initInternal 循环调用Host子容器的init接口。
- startInternal 循环调用Host子容器的start接口。
###### 2.3.5、Host容器接口以及Host容器的实现StandHost
Host容器是解析server.xml时对应的Host标签的内容,定义了Host名称name,Webapp的主目录addBase等信息,定义了相关业务接口设置该信息。与此同时,需要维护父容器Engine和子容器Context之间的关系,主要接口包含:
- setEngine 设置Engine父容器
- getEngine 获取Engine父容器
- setName 设置虚拟主机名称
- getName 获取虚拟主机名称
- setAppBase 设置Webapps的主目录
- getAppBase 获取Webapps的主目录
- addContext 添加上下文子容器Context
- getContextes 获取所有上下文子容器
StandHost实现了Host容器接口,并且继承LifeCycleBase接口类。
- initInternal 循环调用子容器Context的初始化方法init
- startInternal 循环调用子容器Context的启动方法start
###### 2.3.6、Context容器接口以及Context容器的实现StandContext
Context对应的是webapp运行的上下文环境,需要在加载的时候将webapp的根目录设置为上下文名称contextName,并且能够将从web.xml中解析出来的Servlet加入到Wapper容器中进行管理,并将wapper交由上下文容器缓存其url和mapper之间的映射关系。与此同时,需要设置web的类加载器,具体接口包含:
- setContextName 设置上下文名称
- getContextName 获取上下文名称
- addWapper 添加servlet容器
- findWapper 根据Url查找servlet容器
- setClassloader 设置WebApp的类加载器
StandContext是Context容器的具体实现,同时继承了LifeCycleBase接口类。
- initInternal 容器初始化接口,通过循环容器中的所有wapper,获取wapper的全限定类名,采用自定义WebApp的类加载器加载Servlet具体实现类,并实例化servlet对象设置到wapper容器中,最后调用servlet的init接口初始化话servlet。
- startInternal 不做具体工作。
###### 2.3.7、Wapper容器以及Wapper容器的实现类StandWapper
Wapper是Servlet容器,主要加载web.xml中定义的servlet和servlet-mapping信息,提供一个容器管理一个Servlet业务规范,与此同时需要设置父容器关系。主要接口包含:
- getServlet 获取Servlet对象
- setServlet 设置Servlet对象
- setUrlPattern 设置URL映射
- getUrlPattern 获取URL映射
- setClassName 设置全限定类名
- getClassName 获取全限定类名
- setServletName 设置名称
- setContext 设置系统上下文容器(父容器)
StandWapper实现了Wapper接口。
##### 2.4、连接组件开发
###### 2.4.1、Connector连接器
连接器是service容器下的一个构成部分,负责管理某一个协议(这里指HTTP协议)的连接与处理。连接器包含端口、所属Service以及协议处理器ProtocolHandler接口。并且Connector继承自LifeCycleBase类,在初始化Service的时候会调用该对象的init接口,Connector的init接口负责初始化协议处理器ProtocolHandler。ProtocolHandler的初始化方法对Endpoint进行初始化,Endpoint负责真正的服务端ServerSocket的端口监听,并进行业务处理。
- getPort 获取监听端口
- setPort 设置监听端口
- setServer 设置所属服务器(这里注意考虑线程池是在server中初始化)
- setService 设置所属服务
- getService 获取所属服务
- initInternal 初始化Connector,调用ProtocolHandler对象初始化方法。
- startInternal启动Connector,调用ProtocolHandler对象启动方法,启动服务。
###### 2.4.2、ProtocolHandler协议处理器以及Http11ProtocolHandler
ProtocolHandler接口描述了协议处理所需的相关依赖接口。包括设置线程池Executor、连接器Connector、处理器终端Endpoint、初始化、启动等方法。这里Http11ProtocolHandler是本例的具体实现。
- setExecutor 设置线程池
- getExecutor 获取线程池
- setConnector 设置连接器
- getConnector 获取连接器
- getPort 获取Connector中设置的端口
- init 调用Endpoint接口的初始化器。
- start 调用Endpoint接口的start方法启动监听。
###### 2.4.3、Endpoint以及BioEndpoint
Endpoint接口时处理网络连接的终端接口,属于ProtocolHhandler的组合组件。ProtocolHandler初始化时会初始化该组件。BioEndpoint是本例的具体实现,采用了BIO模型作为网络处理的模型。
- setProtocolHandler 设置协议处理器
- init 初始化ServerSocket并绑定端口
- start 启动serverSocket监听,一旦接收到客户端监听则创建处理器执行器Processor交给线ProtocolHandler中的线程池处理。
- createProcessor 传入接收的客户端Socket对象以及适配器Adapter(本例适配器对象在构造BioEndpoint时传入)实例化Processor对象。
###### 2.4.4、Processor处理器执行器
Processor对象实现了Runnable接口,由线程池执行该类的run方法。
- run 获取Socket的输入流和输出流,并构造Request和Response对象,调用Adapter适配器的service方法执行处理。
###### 2.4.5、Adapter适配器以及CoyotoAdapter适配器
Adapter主要实现将Request对象和Response对象实现和容器组件进行关联、处理映射以及处理请求响应的过程。需要设置CoyotoAdapter适配器的所属Connector组件。
- service 适配器提供service接口,该结构上processor对象生产的Request对象和Response对象作为参数传递到该接口中。接口处理主要分为两个部分,1)根据请求的Host内容和连接中url参数查找Context容器;2)在context容器中根据url查找对应的Wapper处理器,如果没有遍历到,则按照静态资源输出到客户端,否则调用容器的servlet的service方法处理请求并响应。
##### 2.5、初始化流程
系统的初始化流程是在Bootstrap类中的startV4方法中展开。首先需要编辑好resources目录下的server.xml文件,startV4接口调用了init方法和start4方法,并别表示初始化容器和启动容器。其中init流程分为load流程和server.init容器流程。
###### 2.5.1、server.xml配置
```xml
```
在Host节点中配置的/users/webapps目录下,将dome1和demo2目录拷贝到对应的位置,表示minicat将发布demo1和demo2两个webApp。
###### 2.5.2、demo中web.xml配置
```xml
lagou
com.lagou.edu.servlet.Demo1Servlet
lagou
/lagou
```
两个目录均是初始化com.lagou.edu.servlet.Demo1Servlet类,分别由demo1和demo1工程编译的.class文件。二者在处理响应时打印结果不一样,但是类名完全一致,必须在Context容器初始化时,能够使用绑定的自定义WebAppClassLoader的类加载器,实现类加载。
###### 2.5.3、load流程
- 调用load方法,读取server.xml文件创建Server接口。
- 解析所有Service节点,分别调用createService创建Service容器,并将容器加入到Server对象中管理。
- createServeice方法创建Service容器,需要解析/Service/Connector节点和Engine节点,分别调用createEngine方法创建Engine容器和构建Connector连接器组件,连接器Connector组件需要设置Adapter、Endpoint、ProtocolHandler等相关接口的相关依赖关系,最后将连接器交由server管理。
- createEngine方法创建Engine容器,构建Engine接口的对象,并调用createHost方法创建Host虚拟主机容器接口,并将所有的Host交由engine对象进行管理。
- createHost方法创建Host容器,解析XML中的Host节点信息,并且遍历appBase目录下的子目录,并将子目录web通过调动createContext接口创建Context容器,最后将所有的Context容器交给Host管理。
- createContext方法创建Context容器,为每个context容器设置一个自定义类加载器WebAppClassloader。最后调用createWapper方法加载context的web目录下的/WEB-INF/web.xml文件,初始化Wapper容器。
- createWapper方法创建Wapper容器。解析web.xml并且将相关属性设置到Wapper容器中,最后将wapper容器交给context容器进行管理。
###### 2.5.4、server.init容器初始化流程
- server初始化 : 调用所有service容器的init方法;调用所有Connector对象的init方法初始化连接器;初始化全局线程池对象;
- service初始化:调用所有Engine容器的init方法;
- Engine初始化:调用所有hosts容器的init方法;
- Host初始化:调用所有Context容器的init方法;
- Context初始化:将所有wapper容器生成servlet实例对象,并调用servlet的init接口,初始化Wapper容器。
- Connector初始化:调用ProtocolHandler的init接口。
- ProtocolHandler初始化:调用Endpoint的init接口。
- Endpoint初始化:启动服务端监听。
##### 2.6、启动流程
系统初始化完成之后需要启动容器以及连接器,让连接器产生监听。Minicat的启动通过start4方法。
Server启动:调用所有service容器的start方法;调用所有Connector对象的init方法启动连接器;
Service启动:调用所有Engine容器的start方法;
Engine启动:调用所有Host容器的start方法;
Host启动:调用所有Context容器的start方法;
Context启动:
Connector启动:调用ProtocolHandler的start方法;
ProtocolHandler启动:调用Endpoint的start方法;
Endpoint启动:开启接收客户端请求。
##### 2.7、系统运行示例
###### 2.7.1、系统启动
运行bootstrap的main方法,启动日志如下所示:
```
com.lagou.edu.minicat.container.impl.StandServer init begin
com.lagou.edu.minicat.container.impl.StandService init begin
com.lagou.edu.minicat.container.impl.StandEngine init begin
com.lagou.edu.minicat.container.impl.StandHost init begin
com.lagou.edu.minicat.container.impl.StandContext init begin
init
com.lagou.edu.servlet.Demo1Servlet init
com.lagou.edu.minicat.container.impl.StandContext init finished
com.lagou.edu.minicat.container.impl.StandContext init begin
init
com.lagou.edu.servlet.Demo1Servlet init
com.lagou.edu.minicat.container.impl.StandContext init finished
com.lagou.edu.minicat.container.impl.StandHost init finished
com.lagou.edu.minicat.container.impl.StandEngine init finished
com.lagou.edu.minicat.container.impl.StandService init finished
com.lagou.edu.minicat.connector.Connector init begin
com.lagou.edu.minicat.connector.impl.BioEndpoint init port 8080
com.lagou.edu.minicat.connector.impl.Http11ProtocolHandler init.
com.lagou.edu.minicat.connector.Connector init finished
com.lagou.edu.minicat.container.impl.StandServer init finished
com.lagou.edu.minicat.container.impl.StandServer start begin
com.lagou.edu.minicat.container.impl.StandService start begin
com.lagou.edu.minicat.container.impl.StandEngine start begin
com.lagou.edu.minicat.container.impl.StandHost start begin
com.lagou.edu.minicat.container.impl.StandContext start begin
com.lagou.edu.minicat.container.impl.StandContext startContext
com.lagou.edu.minicat.container.impl.StandContext start finished
com.lagou.edu.minicat.container.impl.StandContext start begin
com.lagou.edu.minicat.container.impl.StandContext startContext
com.lagou.edu.minicat.container.impl.StandContext start finished
com.lagou.edu.minicat.container.impl.StandHost start finished
com.lagou.edu.minicat.container.impl.StandEngine start finished
com.lagou.edu.minicat.container.impl.StandService start finished
com.lagou.edu.minicat.connector.Connector start begin
com.lagou.edu.minicat.connector.impl.BioEndpoint start recv.
```
###### 2.7.2、访问静态网页
访问http://localhost:8080/demo1/index.html

###### 2.7.3、访问动态网页
访问http://localhost:8080/demo1/lagou

###### 2.7.4、访问demo1和demo2的lagou servlet
访问http://localhost:8080/demo2/lagou

#### 三、Tomcat体系结构
1. Tomcat是一款实现了Servlet/JSP规范的Web容器。
2. Tomcat能够处理http\https等通信协议。
3. Tomcat体系结构主要包括:
Server
Service
Engine
Connector
Host
Context
它们之间的关系如下图所示:

Tomcat通过Cataline将server.xml解析并实例化Server实例,一个Server实例包含多个Service容器实例,Service由多个连接器和连接器Connector和一个Engine构成,Connector负责处理外部应用程序(如浏览器)发起的请求协议,Connector将连接信息封装成为Request请求对象和Response响应对象,并通过适配器Adaptor到转换成容器可以请求和响应对象,与Engine容器进行通信。一个Engine容器由多个Host虚拟主机对象构成,每个Host可以appBase下的子目录加载成多个Context对象,通过解析web.xml将Servlet封装到Wapper容器中进行管理,即一个Context包含多个Wapper。浏览器发出的请求信息,通过Mapper映射器找到请求对应的Wapper容器,并将web.xml中定义的过滤器Filter一起构成FilterChain过滤器链执行servlet的service方法。最后将处理的信息通过response返回给调用端的过程。