创作缘由
平常使用 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,然后解压:其实比较重要的就是 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('\\', '/');
- }
- }
复制代码 开源地址
mini-cat 是简易版本的 tomcat 实现。别称【嗅虎】(心有猛虎,轻嗅蔷薇。)
开源地址:https://github.com/houbb/minicat
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |