深度理解Tomcat底层机制

Posted Al_tair

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度理解Tomcat底层机制相关的知识,希望对你有一定的参考价值。

Tomcat

大家好呀,我是小笙,我和大家分享下我学习Javaweb的笔记

Tomcat

概述

BS 与 CS 开发介绍

(1) 兼容性 , 浏览器的种类很多
(2) 安全性, 通常情况下,BS 安全性不如 CS 好控制
(3) 易用性, BS 好于 CS, 浏览器方便在线使用
(4) 扩展性, BS 相对统一,只需要写 Server

常用服务器

  1. Tomcat:由 Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它 是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器(免费),Tomcat 本质就是一个 Java 程序, 但是这个 Java 程序可以处理来自浏览器的 HTTP 请求

    Tomcat下载网址

  2. Jboss:是一个遵从 JavaEE 规范的、它支持所有的 JavaEE 规范(免费)

  3. GlassFish: 由 Oracle 公司开发的一款 JavaWeb 服务器,是一款商业服务器,达到产品级质量(应用很少)

  4. Resin:是 CAUCHO 公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了 良好的支持, 性能也比较优良(收费)

  5. 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破坏双亲委派机制带来的面试题

Tomcat打破双亲委派机制执行顺序底层代码原理JVM04_Tomcat JDBC破坏双亲委派机制带来的面试

深度理解React底层实现原理

Java知识体系深度理解

Java SPI 机制源码级深度理解

打破双亲委派JVM:类加载机制深度剖析 - 第8篇