运用层

不同打算机上运用之间的通信,来办理通信双方数据传输的问题。
或者说不同打算机上对应的运用进程之间的通信。
支持的协议有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS DHCP等。
(协议)

表示层

用来规定传输的数据格式以及加解密,格式有,JPEG、ASCll、DECOIC、加密格式等。
【在四层模型里面已经合并到了运用层】

会话层

用来规定开始、掌握和终止一个会话。
对应主机的进程,指本地主机与远程主机正在进行的会话。
【在四层模型里面已经合并到了运用层】

jspresourceutilTomcat进阶进修上篇 Docker

传输层

规定传输数据的协议端口号,以及流控和差错校验。
支持的协议有:TCP UDP等,数据包一旦离开网卡即进入网络传输层。
指定IO模型 BIO NIO AIO等

网络层

进行逻辑地址寻址,实现不同网络之间的路径选择。
(路由选择) 协议有:ICMP IGMP IP(IPV4 IPV6) ARP RARP。

数据链路层

建立逻辑连接、进行硬件地址寻址、差错校验等功能。
(由底层网络定义协议,ATM,FDDI等)将比特组合成字节进而组合成帧,用MAC地址访问介质,能缺点创造但不能纠正。

物理层

建立、掩护、断开物理连接。
(由底层网络定义协议,RJ45,802.3等)【在四层模型里面已经合并到了数据链路层】

1.2.2浏览器访问做事器流程

http要求处理过程

第2步是先建立连接,进行3次握手。

1.3 Tomcat 系统总体架构1.3.1Tomcat处理要求大致流程

由于Tomcat可以处理Http要求,因此称Tomcat为Http做事器。

如果我们直接从浏览器发送要求,Tomcat直接吸收要求,并将要求转发到对应的java程序的话,也可以实现要求处理,但是耦合度非常高,因此Tomcat的做法是在吸收到http要求之后,将要求转发给servlet容器,由servlet容器在进行处理并转发到对应的java程序。

因此在Tomcat内部也实现了Servlet规范。
(Servlet接⼝和Servlet容器这⼀整套内容叫作Servlet规范。

因此Tomcat有两个身份:

1、Http做事器

2、Servlet容器

1.3.2Tomcat Servlet容器处理过程

步骤解释:

1)Tomcat中Http做事器模块会吸收到原始的要求参数Request,封装ServletRequest准备要求Servlet容器

2)将要求转发到Servlet容器中定位Servlet(URL和Servlet的映射关系,找到相应的Servlet)

3)如果Servlet还未加载,利用反射机制创建Servlet,并调用Servlet的init初始化方法

4)获取到详细的Servlet实例之后直接调用对应的业务处理方法实行业务

5)将处理好的相应结果封装成ServletResponse

6)Http做事器在将ServletResponse工具封装成原生的Response相应到浏览器

1.3.3Tomcat系统总体架构总结

Tomcat中包括两大核心组件:

连接器(Connector)组件,容器(Container)组件。
(还包括其他组件)

连接器(Connector)组件紧张浸染:处理Socket连接,卖力⽹络字节流与Request和Response工具的转化。
【与客户端交互】

容器(Container)组件紧张浸染:加载和管理Servlet,处理Request要求;

1.4Tomcat组件1.4.1连接器组件 Coyote1)Coyote简介

Coyote是Tomcat中连接器的组件名称,是对应的接口。
客户端通过Coyote与做事器建立连接、发送要求并接管相应。

2)紧张职责

1)Coyote封装了底层网络通信(Socket要求及相应处理)

2)Coyote使Container容器组件与详细的要求协议及IO操作⽅式完备解耦

3)Coyote将Socket输入转换封装为Request工具,并进一步封装成ServletRequest交给Container容器进行处理,处理完成后返回ServletResponse给Coyote,Coyote将工具转换成Response工具将结果写入输出流。

4)Coyote卖力的是详细协议(应⽤层)和IO(传输层)干系内容。

3)Tomcat Coyote支持的IO模型与协议

支持的协议

运用层运用层描述描述HTTP/1.1大部分Web运用采取的协议【Tomcat8.x默认协议】AJPAJP定向包协议,实现对静态资源的优化以及集群的支配。
HTTP/2HTTP2.0大幅度提升了web性能,属于下一代的HTTP协议但是用的很少。

支持的IO

传输层IO模型描述NIO同步非壅塞I/O、采取javaNIO类库实现【Tomcat8默认IO模型】NIO2异步非壅塞I/O、采取jdk7的NIO类库实现APR采取Apache可移植运行库实现,是C/C++编写确当地库,如果利用须要单独安装APR库。

Tomcat在8.0之前默认利用的是BIO。
如果利用APR性能可能达到Apache Http Server的性能。

4)Coyote内部组件

Coyote组件个中包括EndPoint组件、Processor组件、Adapter组件。

EndPoint:EndPoint 是 Coyote 通信端点,即通信监听的接⼝,是详细Socket吸收和发送处理器,是对传输层的抽象,因此EndPoint⽤来实现TCP/IP协议的。

Processor:Processor 是Coyote 协议处理接⼝,如果说EndPoint是⽤来实现TCP/IP协议的,那么Processor⽤来实现HTTP协议,Processor吸收来⾃EndPoint的Socket,读取字节流解析成Tomcat的 Request和Response原生工具。

Adapter:Tomcat Request工具不是标准的ServletRequest,不能⽤Tomcat Request作为参数来调⽤容器。
Tomcat设计者的办理⽅案是引⼊CoyoteAdapter,将参数转换成ServlerRequest工具。

ProtocolHandler:由Endpoint 和 Processor组成,Tomcat 按照协议和I/O 供应了6个实现类 : AjpNioProtocol,AjpAprProtocol,AjpNio2Protocol,Http11NioProtocol,Http11Nio2Protocol,Http11AprProtocol。

1.4.2Tomcat Catalina组件

1)Catalina组件地位

本来Catalina组件只是Servlet容器的一个组件,而Tomcat是由一些列组件组成,组件可以在conf/server.xml文件中配置。
Catalina在Tomcat中的地位非常的核心,因此常常把tomcat的一个实例当作一个Catalina实例。

2)Catalina构造

全体Tomcat就相称于一个Catalina实例,Tomcat启动的时候会先初始化这个实例Catalina,Catalina实例工具通过加载server.xml完成其他实例的创建,创建并管理⼀个Server,Server创建并管理多个做事,每个做事⼜可以有多个Connector和⼀个Container。

对应关系:一个Tomcat对应一个Catalina,对应一个Server,对应多个Service。
每一个Service实例有多个Connector和一个Container实例。

Catalina:卖力解析Tomcat的配置⽂件(server.xml) , 以此来创建做事器Server组件并进⾏管理

Server:Server是全体Catalina Servlet容器以及其它组件,浸染卖力组装并启动Servlaet引擎,Tomcat连接器。
Server通过实现Lifecycle接⼝,供应了⼀种优雅的启动和关闭全体系统的⽅式。

Service:Service是Server内部的组件,⼀个Server包含多个Service。
它将若⼲个Connector组件绑定到⼀个Container。

Container:容器,卖力处理⽤户的servlet要求,并返回工具给web⽤户的模块。

3)Container 组件先容

Container组件个中包括Engine、Host、Context、Wrapper4种组件,他们之间是父子关系。
Tomcat通过分层的架构,让Servlet容用具有很好的灵巧性。

Engine:表示全体Servlet容器的引擎,用来管理多个虚拟站点,一个Service只能有一个Engine。

Host:代表一个虚拟主机,或者说一个站点,可以配置多个虚拟主机地址,一个Engine可以有多个Host。

Context:表示一个Web运用做事器,一个Host下可以包含多个Context。

Wrapper:表示一个Servlet, 一个Context中可以包括多个Wrapper。

2、Tomcat核心配置

思考:

去哪儿配置?->conf/server.xml中

怎么配置?

2.1server.xml配置详解2.1.1server配置文件概述

server.xml中包括Server根标签,Listener,GlobalNamingResources,Service

Server标签:紧张用来创建一个server实体工具

Listener标签:定义监听器

GlobalNamingResources 标签:定义做事器的全局JNDI(Java Naming and Directory Interface 标准的Java命名系统接口)资源。

Service标签:定义⼀个Service做事,⼀个Server标签可以有多个Service做事实例

Server.xml整体构造

<?xml version=&#34;1.0" encoding="UTF-8"?><!--port:关闭做事器的监听端⼝shutdown:关闭做事器的指令字符串--><Server port="8005" shutdown="SHUTDOWN"> <!-- 以⽇志形式输出做事器 、操作系统、JVM的版本信息 --> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <!-- Security listener. Documentation at /docs/config/listeners.html <Listener className="org.apache.catalina.security.SecurityListener" /> --> <!--APR library loader. Documentation at /docs/apr.html --> <!-- 加载(做事器启动) 和 销毁 (做事器停⽌) APR。
如果找不到APR库, 则会输出⽇志, 并 不影响 Tomcat启动 --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <!-- Prevent memory leaks due to use of particular java/javax APIs--> <!-- 避免JRE内存泄露问题 --> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <!-- 加载(做事器启动) 和 销毁(做事器停⽌) 全局命名做事 --> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <!-- 在Context停⽌时重修 Executor 池中的线程, 以避免ThreadLocal 干系的内存泄露 --> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <!-- Global JNDI resources Documentation at /docs/jndi-resources-howto.html GlobalNamingResources 中定义了全局命名做事 --> <GlobalNamingResources> <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <!-- A "Service" is a collection of one or more "Connectors" that share a single "Container" Note: A "Service" is not itself a "Container", so you may not define subcomponents such as "Valves" at this level. Documentation at /docs/config/service.html --> <Service name="Catalina"> ... </Service></Server>

2.1.2Service标签

<Server port="8005" shutdown="SHUTDOWN"> .... <Service name="Catalina"> <!--为Connector创建一个线程池--> <!-- <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/> --> <!--创建一个监听8080的连接器组件 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- 创建连接池的连接器 --> <!-- <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> --> <!-- 创建一个监听8009的ajp的connector --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <!--创建引擎 管理 多个Host--> <Engine name="Catalina" defaultHost="localhost"> <!--配置集群--> <!-- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <!--host来管理各个Servlet--> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!--servlet--> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service></Server>

Service标签包括Executor 、Connector、Engine、Host等子标签。

Executor标签

<Executor name="commonThreadPool" <!--指定当前哨程的名字 相称于Id--> namePrefix="thread-exec-" <!-- namePrefix 给线程指定前缀名字 --> maxThreads="200" <!--指定最大线程数 --> minSpareThreads="100" <!-- 指定核心线程数 --> maxIdleTime="60000" <!-- 指定线程空闲韶光 超过该韶光线程被自动销毁单位是毫秒 --> maxQueueSize="Integer.MAX_VALUE" <!-- 壅塞行列步队的大小最大值 --> prestartminSpareThreads="false" <!--确定线程池时是否启动核心线程--> threadPriority="5" <!--线程中的优先级默认是5 取值范围是1到10 --> className="org.apache.catalina.core.StandardThreadExecutor" <!-- 自定义线程池类路径 --> />

Executor紧张浸染是来创建一个线程池,用于连接器Connector利用。

Connector标签

<Connector port="8080" <!--监听的端口号--> protocol="HTTP/1.1" connectionTimeout="20000" <!--连接超时时间单位毫秒--> redirectPort="8443" />

protocol="HTTP/1.1": 当前Connector⽀持的访问协议。
默认为 HTTP/1.1 ,并采⽤⾃动切换机制选择⼀个基于 JAVANIO 的链接器或者基于本地APR的链接器(根据本地是否含有Tomcat确当地库剖断)

redirectPort="8443":当前Connector 不⽀持SSL要求, 吸收到了⼀个要求, 并且也符合security-constraint 约束,须要SSL传输,Catalina⾃动将要求重定向到指定的端⼝。

URIEncoding="UTF-8":⽤于指定编码URI的字符编码, Tomcat8.x版本默认的编码为 UTF-8 , Tomcat7.x版本默认为ISO-8859-1。

executor="commonThreadPool":指定共享线程池的名称,也可以通过maxThreads、minSpareThreads 等属性配置内部线程池。

内部线程Demo

<Connector port="8080" protocol="HTTP/1.1" executor="commonThreadPool" maxThreads="1000" minSpareThreads="100" acceptCount="1000" maxConnections="1000" connectionTimeout="20000" compression="on" <!--是否压缩数据, on是开启压缩 off关闭--> compressionMinSize="2048" <!--压缩的最小容量--> disableUploadTimeout="true" <!--是否许可Servlet容器,正在实行利用一个较长的连接超时--> redirectPort="8443" URIEncoding="UTF-8" />Engine 标签

<Engine name="Catalina" defaultHost="localhost"> ...</Engine>

name属性: ⽤于指定Engine 的名称, 默认为Catalina

defaultHost:默认使⽤的虚拟主机名称, 当客户端要求指向的主机⽆效时, 将交由默认的虚拟主机处

理, 默认为localhost。

Host标签

<Host name="localhost2" appBase="webapps2" unpackWARs="true" autoDeploy="true"> <!--用来指定日志配置文件地址 valve--> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /></Host>

Host标签属于engine的子标签,紧张配置虚拟主机的。
默认可以配置多个,appBase如果不配置context默认访问ROOT文件下的运用。

name:用于指定虚拟主机。

appBase:对应的配置路径

unpackWARs:解压war包默认为true

autoDeploye:自动提交

Context 标签

<Context docBase="/Users/demo/web_demo" path="/web3"></Context>

Context属于Host的子标签,紧张用来映射运用所在的文件,比如上边的访问uri是web3映射到 /Users/demo/web_demo文件夹下。

docBase:Web应⽤⽬录或者War包的支配路径。
可以是绝对路径,也可以是相对付Host appBase的相对路径。

path:Web应⽤的Context 路径。
如果我们Host名为localhost, 则该web应⽤访问的根路径为:localhost:8080/web3。

3、手写大略单纯版本Tomcat3.1剖析

手写一个Tomcat名称叫做Minicat,需求:可以吸收浏览器的http要求,并进行要求处理,处理之后将结果返回给浏览器客户端。

1)供应做事,吸收要求(Socket通信)

2)要求信息封装成Request工具(Response工具)

3)客户端要求资源,资源分为静态资源和动态资源

4)将资源返回给客户端

3.2 V1版本Code

public class Bootstrap { //自定义端口号 public static final int port = 8080; //启动方法 private void start() throws IOException { ServerSocket serverSocket = new ServerSocket(port); System.out.println("启动成功,端口号:" + port); while (true) { Socket accept = serverSocket.accept(); OutputStream outputStream = accept.getOutputStream(); String content = "Hello Word !"; String retResult = HttpProtocolUtil.getHeader200(content.getBytes().length) + content; outputStream.write(retResult.getBytes()); outputStream.close(); } } public static void main(String[] args) { Bootstrap bootstrap = new Bootstrap(); try { bootstrap.start(); } catch (IOException e) { e.printStackTrace(); } }}

封装相应头工具类:

public class HttpProtocolUtil { / 获取200相应结果 / public static String getHeader200(int size){ return "HTTP/1.1 200 OK \n" + "Content-Type: text/html \n" + "Content-Length: " + size + " \n" + "\r\n"; } / 获取404相应结果 / public static String getHeader404(){ String str404 = "<p1>404 Not Found</p1>"; return "HTTP/1.1 404 Not Found \n" + "Content-Type: text/html \n" + "Content-Length: " + str404.length() + " \n" + "\r\n" + str404; }}

总结:V1版本的代码比较大略,便是大略在页面上写输入一个8080返回一个Hello Minicat但是须要把稳在返回结果中必须添加上html相应头信息浏览器才能显示

3.3 V2版本Code

哀求:能够输出静态资源文件。

3.3.1 不雅观察要求参数

private void start() throws IOException { ServerSocket serverSocket = new ServerSocket(port); while (true){ Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); //防止网络颠簸读取不到参数 int count = 0; while (count == 0) { count = inputStream.available(); } byte[] bytes = new byte[count]; inputStream.read(bytes); System.out.println(new String(bytes)); socket.close(); }}

打印的参数

GET / HTTP/1.1

Host: localhost:8080

Connection: keep-alive

Cache-Control: max-age=0

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9

Sec-Fetch-Site: none

Sec-Fetch-Mode: navigate

Sec-Fetch-User: ?1

Sec-Fetch-Dest: document

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9

只提取一些有用的要求信息,比如GET、/ 路径信息、参数信息。
来封装成Request工具和Response工具。

3.3.2完成V2版本的CodeBootstrap启动类

public class Bootstrap { private static final int port = 8080; public static void main(String[] args) { Bootstrap bootstrap = new Bootstrap(); try { bootstrap.start(); } catch (IOException e) { e.printStackTrace(); } } / V2.0版本 / private void start() throws IOException { ServerSocket serverSocket = new ServerSocket(port); System.out.println("启动成功"); while (true){ Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); //获取到输入输出工具 Request request = new Request(inputStream); Response response = new Response(outputStream); //将结果写到输出流中 response.outputHtml(request.getUrl()); //一定要把socket关闭 socket.close(); } }}Request工具

@Data@NoArgsConstructorpublic class Request { //要求办法GET、POST private String methodType; //要求URL private String url; //输入流 private InputStream inputStream; / 布局器 / public Request(InputStream inputStream) throws IOException { this.inputStream = inputStream; parseInputParam(inputStream); } //解析参数 private void parseInputParam(InputStream inputStream) throws IOException { //只提取第一行 int length = 0; while (length == 0){ length = inputStream.available(); } byte[] bytes = new byte[length]; inputStream.read(bytes); String inputStr = new String(bytes); //截取出来 GET / HTTP/1.1 String[] split = inputStr.split("\\n"); String[] infoArr = split[0].split(" "); this.methodType = infoArr[0]; this.url = infoArr[1]; System.out.println("=====>>method:" + methodType); System.out.println("=====>>url:" + url); }}Response相应工具

@Data@AllArgsConstructor@NoArgsConstructorpublic class Response { private OutputStream outputStream; //V2版本只输出静态资源文件 public void outputHtml(String path) throws IOException { //获取到文件的绝对路径 String absolutePath = StaticResourceUtil.getAbsolutePath(path); File file = new File(absolutePath); if (file.exists() && file.isFile()) { //调用工具类输出文件 StaticResourceUtil.outputStaticResource(new FileInputStream(file), outputStream); }else{ //404 Not Found output(HttpProtocolUtil.getHeader404()); } } //输出文件 private void output(String path) throws IOException { outputStream.write(path.getBytes()); }}

静态资源处理工具

public class StaticResourceUtil { / 获取到文件的绝对路径并且更换\\为/方便linux识别 / public static String getAbsolutePath(String path) { //获取到当前的绝对路径 String absolutePath = StaticResourceUtil.class.getResource("/").getPath(); return (absolutePath + path).replaceAll("\\\\", "/"); } / 根据输入流 对文件进行输出 @param inputStream 输入流 @param outputStream 输出流 / public static void outputStaticResource(InputStream inputStream, OutputStream outputStream) throws IOException { //缓冲区 int buffer = 1024; int actualOutSize = 0; //获取须要输出文件流的长度 int outputSize = 0; while (outputSize == 0){ outputSize = inputStream.available(); } //输出要求头 outputStream.write(HttpProtocolUtil.getHeader200(outputSize).getBytes()); byte[] bytes = new byte[buffer]; while (actualOutSize < outputSize){ //如果末了不足一个缓冲区的话须要获取到末了的数据length if (actualOutSize + buffer > outputSize) { buffer = outputSize - actualOutSize; bytes = new byte[buffer]; } //从输入流中读取 inputStream.read(bytes); //写出到输出流 outputStream.write(bytes); //刷新输出流 outputStream.flush(); actualOutSize += buffer; } }}

总结: 底层利用的是JavaSocket编程,便是对应输入和输出流进行了封装,截取了须要的信息。

3.4 V3版本Code

需求,能够吸收静态和动态资源,利用线程池吸收。

基于V2版本Request和Response进行开拓。

添加Pom Dom4j用来配置servlet

<dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.6</version> </dependency></dependencies>

web.xml配置文件

<?xml version="1.0" encoding="UTF-8"?><web-app> <servlet> <servlet-name>myServlet</servlet-name> <servlet-class>com.tomcat.demo.servlet.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>myServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping></web-app>Servlet

public interface Servlet { //初始化 void init() throws Exception; //销毁 void destroy() throws Exception; //实行要求 void service(Request request, Response response) throws Exception;}public abstract class HttpServlet implements Servlet { public abstract void doGet(Request request, Response response)throws Exception; public abstract void doPost(Request request, Response response)throws Exception; @Override public void service(Request request, Response response) throws Exception { if ("GET".equalsIgnoreCase(request.getMethodType())) { doGet(request,response); }else { doPost(request,response); } }}public class MyServlet extends HttpServlet { @Override public void doGet(Request request, Response response) throws Exception { doPost(request,response); } @Override public void doPost(Request request, Response response) throws Exception { String content = "<H1>Hello Servlet</H1>"; String header200 = HttpProtocolUtil.getHeader200(content.getBytes().length); response.output(header200 + content); } @Override public void init() throws Exception { System.out.println("初始化方法..."); } @Override public void destroy() throws Exception { System.out.println("销毁方法..."); }}BootStrap启动类

public class Bootstrap { private static final int port = 8080; private Map<String, Servlet> servletMap = new HashMap<>(); public static void main(String[] args) { Bootstrap bootstrap = new Bootstrap(); try { bootstrap.start(); } catch (IOException e) { e.printStackTrace(); } } / 启动tomcat / private void start() throws IOException { ServerSocket serverSocket = new ServerSocket(port); //解析web.xml parseWebXml(); //创建一个线程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 20,//指定核心线程数 100,//指定最大线程数 100L,//指定存活韶光 TimeUnit.MILLISECONDS,//指定时间格式 new LinkedBlockingDeque<>(1000));//设置壅塞行列步队大小 while (true){ //获取到socket Socket socket = serverSocket.accept(); //通过线程池去实行 threadPool.execute(new RequestProcessor(socket, servletMap)); } } private void parseWebXml() { try { InputStream resourceAsStream = this.getClass().getResourceAsStream("/web-apps/WEB-INF/web.xml"); Document document = new SAXReader().read(resourceAsStream); Element rootElement = document.getRootElement(); Element servletElement = (Element) rootElement.selectSingleNode("servlet"); String servletName = servletElement.selectSingleNode("servlet-name").getStringValue(); String servletClass = servletElement.selectSingleNode("servlet-class").getStringValue(); Element servletMapping = (Element) rootElement.selectSingleNode("servlet-mapping[servlet-name = '" + servletName + "']"); String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue(); servletMap.put(urlPattern, (Servlet) Class.forName(servletClass).newInstance()); } catch (Exception e) { e.printStackTrace(); } }}RequestProcessor要求处理类

@Data@AllArgsConstructor@NoArgsConstructorpublic class RequestProcessor implements Runnable { private Socket socket; private Map<String, Servlet> servletMap; @Override public void run() { try { InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); Request request = new Request(inputStream); Response response = new Response(outputStream); //动态资源 if (servletMap.containsKey(request.getUrl())) { servletMap.get(request.getUrl()).service(request, response); }else { //静态资源 response.outputHtml(request.getUrl()); } //关闭当前socket socket.close(); }catch (Exception e){ e.printStackTrace(); } }}

总结:书写Mini版本的Tomcat感想熏染一下Tomcat整体的处理思路。