美文网首页
从零手写实现 tomcat-07-war 如何解析处理三方的 w

从零手写实现 tomcat-07-war 如何解析处理三方的 w

作者: 老马啸西风2020 | 来源:发表于2024-05-09 08:54 被阅读0次

    创作缘由

    平时使用 tomcat 等 web 服务器不可谓不多,但是一直一知半解。

    于是想着自己实现一个简单版本,学习一下 tomcat 的精髓。

    系列教程

    从零手写实现 apache Tomcat-01-入门介绍

    从零手写实现 apache Tomcat-02-web.xml 入门详细介绍

    从零手写实现 tomcat-03-基本的 socket 实现

    从零手写实现 tomcat-04-请求和响应的抽象

    从零手写实现 tomcat-05-servlet 处理支持

    从零手写实现 tomcat-06-servlet bio/thread/nio/netty 池化处理

    从零手写实现 tomcat-07-war 如何解析处理三方的 war 包?

    从零手写实现 tomcat-08-tomcat 如何与 springboot 集成?

    从零手写实现 tomcat-09-servlet 处理类

    从零手写实现 tomcat-10-static resource 静态资源文件

    从零手写实现 tomcat-11-filter 过滤器

    从零手写实现 tomcat-12-listener 监听器

    前言

    到目前为止,我们处理的都是自己的 servlet 等。

    但是 tomcat 这种做一个 web 容器,坑定要能解析处理其他的 war 包。

    这个要如何实现呢?

    1-war 包什么样的?

    源码

    直接用一个 web 简单的项目。

    https://github.com/houbb/servlet-webxml

    项目目录

    mvn clean
    tree /f
    
    D:.
    │
    └─src
        └─main
            ├─java
            │  └─com
            │      └─github
            │          └─houbb
            │              └─servlet
            │                  └─webxml
            │                          IndexServlet.java
            │
            └─webapp
                │  index.html
                │
                └─WEB-INF
                        web.xml
    

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.github.houbb</groupId>
        <artifactId>servlet-webxml</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <plugin.tomcat.version>2.2</plugin.tomcat.version>
        </properties>
    
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-servlet-api</artifactId>
                <version>9.0.0.M8</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    
        <build>
            <finalName>servlet</finalName>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>${plugin.tomcat.version}</version>
                    <configuration>
                        <port>8080</port>
                        <path>/</path>
                        <uriEncoding>${project.build.sourceEncoding}</uriEncoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4"
             xmlns="http://java.sun.com/xml/ns/j2ee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
        <!--默认的欢迎页面-->
        <welcome-file-list>
            <welcome-file>/index.html</welcome-file>
        </welcome-file-list>
    
        <servlet>
            <servlet-name>index</servlet-name>
            <servlet-class>com.github.houbb.servlet.webxml.IndexServlet</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>index</servlet-name>
            <url-pattern>/index</url-pattern>
        </servlet-mapping>
    
    </web-app>
    

    index.html

    <!DOCTYPE html>
    <html>
    <body>
    Hello Servlet!
    </body>
    </html> 
    

    servlet

    package com.github.houbb.servlet.webxml;
    
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    /**
     * @author binbin.hou
     * @since 0.1.0
     */
    public class IndexServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            resp.setContentType("text/html");
    
            // 实际的逻辑是在这里
            PrintWriter out = resp.getWriter();
            out.println("<h1>servlet index</h1>");
        }
    
    }
    

    目录结构

    打包成 war,然后解压:

    mvn clean install
    

    其实比较重要的就是 web.xml 作为一切的入口。

    对应的 war

    D:.
    │  index.html
    │
    ├─META-INF
    │  │  MANIFEST.MF
    │  │
    │  └─maven
    │      └─com.github.houbb
    │          └─servlet-webxml
    │                  pom.properties
    │                  pom.xml
    │
    └─WEB-INF
        │  web.xml
        │
        └─classes
            └─com
                └─github
                    └─houbb
                        └─servlet
                            └─webxml
                                    IndexServlet.class
    

    如何根据类路径加载类信息?类不是当前项目的

    JVM-09-classloader

    核心实现

    package com.github.houbb.minicat.support.classloader;
    
    
    import java.io.IOException;
    import java.io.UncheckedIOException;
    import java.net.URI;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * https://www.liaoxuefeng.com/wiki/1545956031987744/1545956487069728
     *
     * 每一个 dir 的 classLoader 独立。
     */
    public class WebAppClassLoader extends URLClassLoader {
    
        private Path classPath;
        private Path[] libJars;
    
        public WebAppClassLoader(Path classPath, Path libPath) throws IOException {
            super(createUrls(classPath, libPath), ClassLoader.getSystemClassLoader());
    //        super("WebAppClassLoader", createUrls(classPath, libPath), ClassLoader.getSystemClassLoader());
    //
            this.classPath = classPath.toAbsolutePath().normalize();
            if(libPath.toFile().exists()) {
                this.libJars = Files.list(libPath).filter(p -> p.toString().endsWith(".jar")).map(p -> p.toAbsolutePath().normalize()).sorted().toArray(Path[]::new);
            }
        }
    
        static URL[] createUrls(Path classPath, Path libPath) throws IOException {
            List<URL> urls = new ArrayList<>();
            urls.add(toDirURL(classPath));
    
            //lib 可能不存在
            if(libPath.toFile().exists()) {
                Files.list(libPath).filter(p -> p.toString().endsWith(".jar")).sorted().forEach(p -> {
                    urls.add(toJarURL(p));
                });
            }
    
            return urls.toArray(new URL[0]);
        }
    
        static URL toDirURL(Path p) {
            try {
                if (Files.isDirectory(p)) {
                    String abs = toAbsPath(p);
                    if (!abs.endsWith("/")) {
                        abs = abs + "/";
                    }
                    return URI.create("file://" + abs).toURL();
                }
                throw new IOException("Path is not a directory: " + p);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
    
        //D:\github\minicat\src\test\webapps\servlet\WEB-INF\classes
        //D:\github\minicat\src\test\webapps\WEB-INF\classes
    
        static URL toJarURL(Path p) {
            try {
                if (Files.isRegularFile(p)) {
                    String abs = toAbsPath(p);
                    return URI.create("file://" + abs).toURL();
                }
                throw new IOException("Path is not a jar file: " + p);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
    
        static String toAbsPath(Path p) throws IOException {
            return p.toAbsolutePath().normalize().toString().replace('\\', '/');
        }
    
    }
    

    开源地址

     /\_/\  
    ( o.o ) 
     > ^ <
    

    mini-cat 是简易版本的 tomcat 实现。别称【嗅虎】(心有猛虎,轻嗅蔷薇。)

    开源地址:https://github.com/houbb/minicat

    相关文章

      网友评论

          本文标题:从零手写实现 tomcat-07-war 如何解析处理三方的 w

          本文链接:https://www.haomeiwen.com/subject/ninjfjtx.html