Erlo

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

2024-05-10 09:29:17 发布   10 浏览  
页面报错/反馈
收藏 点赞

创作缘由

平时使用 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



    4.0.0

    com.github.houbb
    servlet-webxml
    1.0-SNAPSHOT

    
        8
        8
        UTF-8
        2.2
    

    war

    
        
            javax.servlet
            servlet-api
            2.5
            provided
        

        
            org.apache.tomcat
            tomcat-servlet-api
            9.0.0.M8
            provided
        
    

    
        servlet
        
            
                org.apache.tomcat.maven
                tomcat7-maven-plugin
                ${plugin.tomcat.version}
                
                    8080
                    /
                    ${project.build.sourceEncoding}
                
            
        
    


web.xml




    
    
        /index.html
    

    
        index
        com.github.houbb.servlet.webxml.IndexServlet
    

    
        index
        /index
    


index.html




Hello Servlet!

 

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("

servlet index

"); } }

目录结构

打包成 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 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:githubminicatsrctestwebappsservletWEB-INFclasses
    //D:githubminicatsrctestwebappsWEB-INFclasses

    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

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认