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方法
出现如下字样代表启动成功,然后地址栏中输入
http://localhost:8080/first.html
?????为什么是这样。。。。。。
啊!原来没有添加响应头信息
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();
重新启动,访问
结尾
祝大家新年快乐。感谢支持!
其他文章:
码云地址: gitee.com/beany/mySpr…
GitHub地址: github.com/MyBeany/myS…