从零手动实现简易Tomcat

栏目: Java · 发布时间: 5年前

内容简介:Hello大家好,本章我们自己实现一个简易版的tomcat 。有问题可以联系我mr_beany@163.com。另求各路大神指点,感谢程序的运行少不了服务器的支持,而tomcat因其性能稳定,免费等优点,深受 Java 爱好者的喜爱并得到了部分软件开发商的认可,为目前比较流行的 Web 应用服务器。那么到底它是怎么运行的呢?今天我们来实现一个简化版tomcat来感受一下。

Hello大家好,本章我们自己实现一个简易版的tomcat 。有问题可以联系我mr_beany@163.com。另求各路大神指点,感谢

程序的运行少不了服务器的支持,而tomcat因其性能稳定,免费等优点,深受 Java 爱好者的喜爱并得到了部分软件开发商的认可,为目前比较流行的 Web 应用服务器。

那么到底它是怎么运行的呢?今天我们来实现一个简化版tomcat来感受一下。

一:导入解析xml的jar包

<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
</dependency>复制代码

二:编写XML解析类

package com.example.demo.utils;

import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * @author zy
 */
public class XmlUtils {
    /**
     * 定义解析器和文档对象
     */
    public SAXReader saxReader;
    public Document document;

    public XmlUtils(String path) {
        //获取解析器
        saxReader = new SAXReader();
        try {
            //获取文档对象
            document = saxReader.read(path);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取节点下的所有节点
     *
     * @param name
     * @return
     */
    public List<Element> getNodes(String name) {
        Element root = document.getRootElement();
        return root.elements(name);
    }
}
复制代码

三:实现Request和Response

其中Request是对浏览器的请求的封装,而Response是对浏览器请求的响应,换而言之就是Request 用来取出请求信息,而 Response 则用来添加要返回给浏览器的信息。

创建Request.java

package com.example.demo.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * @author zy
 */
public class Request {

    private String method;

    private String url;

    public Request(InputStream inputStream) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String[] methodAndUrl = bufferedReader.readLine().split(" ");
        this.method = methodAndUrl[0];
        this.url = methodAndUrl[1];
        System.out.println("请求类型:"+ method);
        System.out.println("请求路径:"+ url);
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
    
}复制代码

创建Response.java

package com.example.demo.http;

import java.io.OutputStream;

/**
 * @author zy
 */
public class Response {

    private OutputStream outputStream;

    private String write;

    public Response(OutputStream outputStream){
        this.outputStream = outputStream;
    }

    public String getWrite() {
        return write;
    }

    public void setWrite(String write) {
        this.write = write;
    }

}复制代码

四:实现Servlet

先做个接口

package com.example.demo.servlet;

import com.example.demo.http.Request;
import com.example.demo.http.Response;

/**
 * @author zy
 */
public abstract class AbstractServlet {

    public abstract void doGet(Request request, Response response);

    public abstract void doPost(Request request, Response response);
}复制代码

再来实现自己的Servlet

package com.example.demo.servlet;

import com.example.demo.http.Request;
import com.example.demo.http.Response;

/**
 * @author zy
 */
public class FirstServlet extends AbstractServlet {

    @Override
    public void doGet(Request request, Response response) {
        response.setWrite("我的第一个Servlet");
    }

    @Override
    public void doPost(Request request, Response response) {
        this.doGet(request, response);
    }
}复制代码

五:创建web.xml

这里配置了请求路径的servlet的对应关系,文件放在resources文件夹下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

    <servlet>
        <servlet-name>first.html</servlet-name>
        <servlet-class>com.example.demo.servlet.FirstServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>first.html</servlet-name>
        <url-pattern>/first.html</url-pattern>
    </servlet-mapping>

</web-app>复制代码

六,创建tomcat,初始化配置文件

package com.example.demo.tomcat;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;

import com.example.demo.utils.XmlUtils;
import org.dom4j.Element;

/**
 * @author zy
 */
public class Tomcat {
    /**
     * 设置端口号
     */
    private static final int PORT = 8080;

    public static final HashMap<String, Object> SERVLET_MAPPING = new HashMap<>();

    public static final HashMap<String, Object> SERVLET = new HashMap<>();

    /**
     * 控制服务器启动关闭
     */
    public boolean tomcatStarBool = true;

    private void init() {
        InputStream io = null;
        try {
            System.out.println("加载配置文件开始");
            //读取配置文件
            XmlUtils xml = new XmlUtils(XmlUtils.class.getResource("/")+"web.xml");
            //将所有的类都存储到容器中
            List<Element> list = xml.getNodes("servlet");
            for (Element element : list) {
                SERVLET.put(element.element("servlet-name").getText(),
                        Class.forName(element.element("servlet-class").getText()).newInstance());
            }
            //映射关系创建
            List<Element> list2 = xml.getNodes("servlet-mapping");
            for (Element element : list2) {
                SERVLET_MAPPING.put(element.element("url-pattern").getText(),
                        element.element("servlet-name").getText());
            }
            System.out.println("加载配置文件结束");
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (io != null) {
                try {
                    io.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

}复制代码

七:创建处理请求任务的SocketProcess

package com.example.demo.tomcat;

import com.example.demo.http.Request;
import com.example.demo.http.Response;
import com.example.demo.servlet.AbstractServlet;

import java.io.OutputStream;
import java.net.Socket;

/**
 * @author zy
 */
public class SocketProcess extends Thread{

    protected Socket socket;

    public SocketProcess(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            Request request = new Request(socket.getInputStream());
            Response response = new Response(socket.getOutputStream());
            String servletName = (String) Tomcat.SERVLET_MAPPING.get(request.getUrl());
            if(servletName!=null && !servletName.isEmpty()) {
                //映射有的话找到对应的对象
                AbstractServlet servlet = (AbstractServlet) Tomcat.SERVLET.get(servletName);
                if(servlet!=null) {
                    servlet.doGet(request, response);
                }else {
                    System.out.println("找不到对应的servlet");
                }
            }else {
                System.out.println("找不到对应的servletMapping");
            }
            String res = response.getWrite();
            OutputStream outputStream = socket.getOutputStream();

            outputStream.write(res.getBytes("GBK"));
            outputStream.flush();
            outputStream.close();

        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}复制代码

八:在tomcat.java中添加启动方法

private void start() {
    try {
        ServerSocket serverSocket = new ServerSocket(PORT);
        System.out.println("Tomcat 服务已启动,地址:localhost ,端口:" + PORT);
        this.init();
        //持续监听
        do {
            Socket socket = serverSocket.accept();
            //处理任务
            Thread thread = new SocketProcess(socket);
            thread.start();
        } while (tomcatStarBool);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    Tomcat tomcat = new Tomcat();
    tomcat.start();
}复制代码

九:测试

启动在tomcat.java中运行void main方法

从零手动实现简易Tomcat

出现如下字样代表启动成功,然后地址栏中输入

http://localhost:8080/first.html

?????为什么是这样。。。。。。 从零手动实现简易Tomcat

啊!原来没有添加响应头信息

Response.java中加入

/**
 * 响应头信息
 */
public static final String RESPONSE_HEADER ="HTTP/1.1 200 \r\n"
        + "Content-Type: text/html\r\n"
        + "\r\n";复制代码

SocketProcess.java中

String res = response.getWrite();复制代码

改成

String res = Response.RESPONSE_HEADER + response.getWrite();复制代码

重新启动,访问

从零手动实现简易Tomcat

结尾

祝大家新年快乐。感谢支持!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Just My Type

Just My Type

Simon Garfield / Profile Books / 2010-10-21 / GBP 14.99

What's your type? Suddenly everyone's obsessed with fonts. Whether you're enraged by Ikea's Verdanagate, want to know what the Beach Boys have in common with easy Jet or why it's okay to like Comic Sa......一起来看看 《Just My Type》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器