深度理解Tomcat底层机制
Posted Al_tair
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度理解Tomcat底层机制相关的知识,希望对你有一定的参考价值。
Tomcat
大家好呀,我是小笙,我和大家分享下我学习Javaweb的笔记
Tomcat
概述
BS 与 CS 开发介绍
(1) 兼容性 , 浏览器的种类很多
(2) 安全性, 通常情况下,BS 安全性不如 CS 好控制
(3) 易用性, BS 好于 CS, 浏览器方便在线使用
(4) 扩展性, BS 相对统一,只需要写 Server
常用服务器
-
Tomcat:由 Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它 是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器(免费),Tomcat 本质就是一个 Java 程序, 但是这个 Java 程序可以处理来自浏览器的 HTTP 请求
-
Jboss:是一个遵从 JavaEE 规范的、它支持所有的 JavaEE 规范(免费)
-
GlassFish: 由 Oracle 公司开发的一款 JavaWeb 服务器,是一款商业服务器,达到产品级质量(应用很少)
-
Resin:是 CAUCHO 公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了 良好的支持, 性能也比较优良(收费)
-
WebLogic:是 Oracle 公司的产品,支持 JavaEE 规范, 而且不断的完善以适 应新的开发要求,适合大型项目(收费,用的不多,适合大公司)
Tomcat 目录结构
Web应用
Tomcat 服务中部署 WEB 应用
概念:Web应用通常也称之为web应用程序(网站),WEB应用是多个web资源的集合
组成
在Tomcat 下的 conf 目录\\Catalina\\localhost\\ 下,配置文件,比如XXX.xml(提醒:通过Tomcat配置,可以把一个web应用,映射到指定的目录,可以解决磁盘空间分配问题
<?xml version="1.0" encoding="utf-8"?>
<!-- Context 表示一个工程上下文 path表示工程的访问路径:/XXX dosBase表示目标工程位置 -->
<Context path:"/XXX" docBase="E:\\Java\\Java_software">
浏览器请求资源过程
注意:http://localhost , 默 认 是 访 问 80 端 口 , 即 http://localhost 等 价 http://localhost:80
IDEA 开发 JavaWeb 注意事项
1.热加载选项说明
2.修改端口,只会影响当前的项目,但是不会去修改tomcat文件中server.xml文件的端口
3.当tomcat启动时,会生成out目录,该目录就是原项目资源的映射,我们浏览器访问的资源是 out 目录
Maven
基本介绍
概述:一个项目管理工具,可以对 Java 项目进行构建、依赖管理
IDEA创建Maven项目说明
pom.xml文件说明
<dependencies>
<!--
1. dependency 表示依赖, 也就是我们这个项目需要依赖的jar包
2. groupId 和 artifactId 被统称为坐标, 是为了去定位这个项目/jar
3. groupId: 一般是公司比如:com.baidu , 这里是 javax.servlet
4. artifactId 一般是项目名, 这里是javax.servlet-api
5. version 表示你引入到我们项目的jar包的版本是 3.1.0
6. scope: 表示作用域,也就是你引入的 jar 包的作用范围
6.1.provided 表示在tomcat服务器中有这个jar包,因此在编译或者测试使用,但是在打包发布就不用要带上该jar包
-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
实现Tomcat底层机制
框架图
实现案例
题目要求
-
可以访问静态资源addSum.html
-
可以通过提交按钮,跳转到求和解结果
文件目录说明
xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<myTomcat>
<myServlet>
<Servlet-name>myTomcat</Servlet-name>
<Servlet-class>com.al_tair.myTomcat.myServlet.CalServlet</Servlet-class>
</myServlet>
<myServlet-mapping>
<Servlet-name>myTomcat</Servlet-name>
<url-pattern>/myTomcat</url-pattern>
</myServlet-mapping>
</myTomcat>
静态资源
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:9999/myTomcat" method="get">
<h1>求和</h1>
第一个数字:<input type="text" name="firstNum"><br>
第二个数字:<input type="text" name="secondName"><br>
<button type="submit">提交</button>
</form>
</body>
</html>
网络监听
public class Connector
// 存放<name,Servlet实例>
public static final ConcurrentHashMap<String, MyHttpServlet>
nameToServlet = new ConcurrentHashMap<>();
// 存放<urlPattern,name>
public static final ConcurrentHashMap<String, String>
urlToName = new ConcurrentHashMap<>();
public static void main(String[] args) throws IOException, InterruptedException
// 在端口9999监听
ServerSocket serverSocket = new ServerSocket(9999);
while(!serverSocket.isClosed())
init();
// 创建套接字 socket
System.out.println("listening...");
Socket socket = serverSocket.accept();
RequestHandler rh = new RequestHandler(socket);
new Thread(rh).start();
public static void init()
String path = Connector.class.getResource("/").getPath();
SAXReader saxReader = new SAXReader();
try
Document document = saxReader.read(new File(path + "web.xml"));
// 得到根元素
Element rootElement = document.getRootElement();
// 得到根元素下的所有元素
List<Element> myServlet = rootElement.elements();
for (Element element: myServlet
)
if("myServlet".equalsIgnoreCase(element.getName()))
Element element1 = element.element("Servlet-name");
Element element2 = element.element("Servlet-class");
nameToServlet.put(element1.getText(),(MyHttpServlet)Class.forName(element2.getText()).newInstance());
else if("myServlet-mapping".equalsIgnoreCase(element.getName()))
Element element1 = element.element("Servlet-name");
Element element2 = element.element("url-pattern");
urlToName.put(element2.getText(),element1.getText());
catch (Exception e)
e.printStackTrace();
线程处理请求和响应
public class RequestHandler implements Runnable
private Socket socket = null;
public RequestHandler(Socket socket)
this.socket = socket;
@Override
public void run()
MyHttpRequest Request = null;
MyHttpResponse Response = null;
try
Request = new MyHttpRequest(socket.getInputStream());
Response = new MyHttpResponse(socket.getOutputStream());
String uri = Request.getUri();
System.out.println(uri);
String path = RequestHandler.class.getResource("/").getPath();
if(Connector.urlToName.containsKey(uri))
String name = Connector.urlToName.get(uri);
if(Connector.nameToServlet.containsKey(name))
MyHttpServlet myHttpServlet = Connector.nameToServlet.get(name);
try
myHttpServlet.service(Request,Response);
catch (Exception e)
e.printStackTrace();
else
OutputStream outputStream = Response.getOutputStream();
int index = uri.indexOf(".");
if(uri.substring(index+1).equalsIgnoreCase("html"))
try
FileReader fileReader = new FileReader(path + "/static" + uri);
BufferedReader br = new BufferedReader(fileReader);
String str = "";
outputStream.write(Response.getResponseHeader().getBytes());
while((str = br.readLine()) != null)
outputStream.write(str.getBytes());
outputStream.flush();
outputStream.close();
catch (Exception e)
e.printStackTrace();
else
outputStream.write((Response.responseHeader + "<h1>404,没有找到该资源</h1>").getBytes());
outputStream.flush();
outputStream.close();
else
OutputStream outputStream = Response.getOutputStream();
int index = uri.indexOf(".");
if(uri.substring(index+1).equalsIgnoreCase("html"))
try
FileReader fileReader = new FileReader(path + "/static" + uri);
BufferedReader br = new BufferedReader(fileReader);
String str = "";
outputStream.write(Response.getResponseHeader().getBytes());
while((str = br.readLine()) != null)
outputStream.write(str.getBytes());
outputStream.flush();
outputStream.close();
catch (Exception e)
e.printStackTrace();
else
outputStream.write((Response.responseHeader + "<h1>404,没有找到该资源</h1>").getBytes());
outputStream.flush();
outputStream.close();
socket.close();
catch (IOException e)
throw new RuntimeException();
请求类和响应类
/**
* 封装http请求数据简化
*/
public class MyHttpRequest
private String uri;
private String method;
private HashMap<String,String> parameters = new HashMap<>();
private InputStream inputStream = null;
public MyHttpRequest(InputStream inputStream)
this.inputStream = inputStream;
init();
public String getUri()
return uri;
public String getMethod()
return method;
public void init()
try
// 将字节流转换成字符流,方便读取数据
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String request = bufferedReader.readLine();
String[] requestLine = request.split(" ");
// GET /servlet?name=18 HTTP/1.1
method = requestLine[0];
int index = requestLine[1].indexOf("?");
if(index == -1)
// uri后面没有数据
uri = requestLine[1];
else
uri = requestLine[1].substring(0,index);
String parameter = requestLine[1].substring(index+1);
String[] params = parameter.split("&");
if(parameter != null && !params.equals(""))
for (String param:params
)
String[] split = param.split("=");
if(split.length == 2)
parameters.put(split[0],split[1]);
catch (IOException e)
throw new RuntimeException();
public String Parameter(String name)
if(parameters.containsKey(name))
return parameters.get(name);
else
return null;
/**
* http响应头封装简化
*/
public class MyHttpResponse
pr以上是关于深度理解Tomcat底层机制的主要内容,如果未能解决你的问题,请参考以下文章
JVM17_Tomcat打破双亲委派机制执行顺序底层代码原理Tomcat|JDBC破坏双亲委派机制带来的面试题