<返回更多

JAVA手写tomcat,带你了解tomcat的原理,附代码

2019-11-20    
加入收藏

1 创建一个简单的servlet

代码示例:

package springmvc;

import JAVA.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet{

/**

* 一个最简单的servlet

*/

private static final long serialVersionUID = 7683475760018217521L;

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String data="这是我的第一个servlet!";

System.out.println(data);

}

}

web.xml中的标签确定了servlet的访问路径

<!DOCTYPE web-App PUBLIC

"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>

<display-name>Archetype Created Web Application</display-name>

<servlet>

<servlet-name>littleServlet</servlet-name>

<servlet-class>springmvc.MyServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>littleServlet</servlet-name>

<url-pattern>/servlet</url-pattern>

</servlet-mapping>

</web-app>

servlet完成之后需要需要将他打包成项目(war/jar),并解压完成,形成完整的项目目录,供后续自己写的Tomcat使用。通常情况下,所有的项目都会放入tomcat的webapps目录下。

开始手动编写tomcat代码

代码示例

package springboot.tomcat;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.PrintWriter;

import java.io.UnsupportedEncodingException;

import java.net.ServerSocket;

import java.net.Socket;

import java.security.Principal;

import java.util.Collection;

import java.util.Enumeration;

import java.util.Locale;

import java.util.Map;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import javax.servlet.AsyncContext;

import javax.servlet.DispatcherType;

import javax.servlet.RequestDispatcher;

import javax.servlet.Servlet;

import javax.servlet.ServletContext;

import javax.servlet.ServletException;

import javax.servlet.ServletInputStream;

import javax.servlet.ServletOutputStream;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.Cookie;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import javax.servlet.http.HttpUpgradeHandler;

import javax.servlet.http.Part;

import springboot.util.ProjectUtil;

/**

* @author liuhongya328

*

*/

public class TomcatServer {

static int threads = 10;

private static ExecutorService pool = Executors.newCachedThreadPool();

/**

* @param args

*/

public static void main(String[] args) throws Exception{

//加载项目,获取tomcat需要发布的所有项目及项目下的所有servlet信息

final Map<String, ProjectUtil.WebXml> projectIno = ProjectUtil.load();

ServerSocket serverSocket = new ServerSocket(8080);

System.out.println("Tomcat 启动成功");

while(!serverSocket.isClosed()) {

//阻塞获取新连接

Socket socket = serverSocket.accept();

pool.submit(()->{

//接收数据

InputStream inputStream = socket.getInputStream();;

//请求响应结果

OutputStream outputStream = socket.getOutputStream();

try {

System.out.println("收到请求:-------");

BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));

String msg = null;

StringBuilder requestInfo = new StringBuilder();

while((msg = reader.readLine())!=null) {

if(msg.length()==0) {

break;

}

requestInfo.append(msg).append("rn");

}

System.out.println(requestInfo.toString()+"--------");

//请求需要访问的servlet,这个servlet相当于业务代码的controller,是需要放入tomcat中启动的项目,用原生的servlet便于从底层代码理解

//1.获取请求方式 及请求路径 GET /SpringMVC/servlet/littleServlet HTTP/1.1

String firstLine = requestInfo.toString().split("rn")[0];

String projectName = firstLine.split(" ")[1].split("/")[1];

String servletPath = firstLine.split(" ")[1].replace("/"+projectName, "");

//找到servlet对应的名称--j2ee规范

String servletName = projectIno.get(projectName).servletMapping.get(servletPath).toString();

//找到servlet对应的实例

Servlet servlet = (Servlet) projectIno.get(projectName).servletInstances.get(servletName);

//将socket的inputsteam 转成 request对象 ,如果想servlet接收和传递消息,需要实现自己的HttpServletRequest/HttpServletResponse即可。

//这里的创建仅作展示,实际没有作用,并不会传递socket的信息。

HttpServletRequest servletReuqest = createRequest();

HttpServletResponse servletResponse = createResponse();

//servlet的生命周期

servlet.service(servletReuqest, servletResponse);

outputStream.write("HTTP/1.1 200 OKrn".getBytes());

outputStream.write("Content-Length: 12rnrn".getBytes());

outputStream.write("Hello World!".getBytes());

outputStream.flush();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

socket.close();

return null;

});

}

serverSocket.close();

}

private static HttpServletRequest createRequest() {

return new HttpServletRequest() {

@Override

public Object getAttribute(String name) {

// TODO Auto-generated method stub

return null;

}

@Override

public Enumeration<String> getAttributeNames() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getCharacterEncoding() {

// TODO Auto-generated method stub

return null;

}

@Override

public void setCharacterEncoding(String env) throws UnsupportedEncodingException {

// TODO Auto-generated method stub

}

@Override

public int getContentLength() {

// TODO Auto-generated method stub

return 0;

}

@Override

public long getContentLengthLong() {

// TODO Auto-generated method stub

return 0;

}

@Override

public String getContentType() {

// TODO Auto-generated method stub

return null;

}

@Override

public ServletInputStream getInputStream() throws IOException {

// TODO Auto-generated method stub

return null;

}

@Override

public String getParameter(String name) {

// TODO Auto-generated method stub

return null;

}

@Override

public Enumeration<String> getParameterNames() {

// TODO Auto-generated method stub

return null;

}

@Override

public String[] getParameterValues(String name) {

// TODO Auto-generated method stub

return null;

}

@Override

public Map<String, String[]> getParameterMap() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getProtocol() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getScheme() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getServerName() {

// TODO Auto-generated method stub

return null;

}

@Override

public int getServerPort() {

// TODO Auto-generated method stub

return 0;

}

@Override

public BufferedReader getReader() throws IOException {

// TODO Auto-generated method stub

return null;

}

@Override

public String getRemoteAddr() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getRemoteHost() {

// TODO Auto-generated method stub

return null;

}

@Override

public void setAttribute(String name, Object o) {

// TODO Auto-generated method stub

}

@Override

public void removeAttribute(String name) {

// TODO Auto-generated method stub

}

@Override

public Locale getLocale() {

// TODO Auto-generated method stub

return null;

}

@Override

public Enumeration<Locale> getLocales() {

// TODO Auto-generated method stub

return null;

}

@Override

public boolean isSecure() {

// TODO Auto-generated method stub

return false;

}

@Override

public RequestDispatcher getRequestDispatcher(String path) {

// TODO Auto-generated method stub

return null;

}

@Override

public String getRealPath(String path) {

// TODO Auto-generated method stub

return null;

}

@Override

public int getRemotePort() {

// TODO Auto-generated method stub

return 0;

}

@Override

public String getLocalName() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getLocalAddr() {

// TODO Auto-generated method stub

return null;

}

@Override

public int getLocalPort() {

// TODO Auto-generated method stub

return 0;

}

@Override

public ServletContext getServletContext() {

// TODO Auto-generated method stub

return null;

}

@Override

public AsyncContext startAsync() throws IllegalStateException {

// TODO Auto-generated method stub

return null;

}

@Override

public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)

throws IllegalStateException {

// TODO Auto-generated method stub

return null;

}

@Override

public boolean isAsyncStarted() {

// TODO Auto-generated method stub

return false;

}

@Override

public boolean isAsyncSupported() {

// TODO Auto-generated method stub

return false;

}

@Override

public AsyncContext getAsyncContext() {

// TODO Auto-generated method stub

return null;

}

@Override

public DispatcherType getDispatcherType() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getAuthType() {

// TODO Auto-generated method stub

return null;

}

@Override

public Cookie[] getCookies() {

// TODO Auto-generated method stub

return null;

}

@Override

public long getDateHeader(String name) {

// TODO Auto-generated method stub

return 0;

}

@Override

public String getHeader(String name) {

// TODO Auto-generated method stub

return null;

}

@Override

public Enumeration<String> getHeaders(String name) {

// TODO Auto-generated method stub

return null;

}

@Override

public Enumeration<String> getHeaderNames() {

// TODO Auto-generated method stub

return null;

}

@Override

public int getIntHeader(String name) {

// TODO Auto-generated method stub

return 0;

}

@Override

public String getMethod() {

//示例

return "GET";

}

@Override

public String getPathInfo() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getPathTranslated() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getContextPath() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getQueryString() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getRemoteUser() {

// TODO Auto-generated method stub

return null;

}

@Override

public boolean isUserInRole(String role) {

// TODO Auto-generated method stub

return false;

}

@Override

public Principal getUserPrincipal() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getRequestedSessionId() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getRequestURI() {

// TODO Auto-generated method stub

return null;

}

@Override

public StringBuffer getRequestURL() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getServletPath() {

// TODO Auto-generated method stub

return null;

}

@Override

public HttpSession getSession(boolean create) {

// TODO Auto-generated method stub

return null;

}

@Override

public HttpSession getSession() {

// TODO Auto-generated method stub

return null;

}

@Override

public String changeSessionId() {

// TODO Auto-generated method stub

return null;

}

@Override

public boolean isRequestedSessionIdValid() {

// TODO Auto-generated method stub

return false;

}

@Override

public boolean isRequestedSessionIdFromCookie() {

// TODO Auto-generated method stub

return false;

}

@Override

public boolean isRequestedSessionIdFromURL() {

// TODO Auto-generated method stub

return false;

}

@Override

public boolean isRequestedSessionIdFromUrl() {

// TODO Auto-generated method stub

return false;

}

@Override

public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {

// TODO Auto-generated method stub

return false;

}

@Override

public void login(String username, String password) throws ServletException {

// TODO Auto-generated method stub

}

@Override

public void logout() throws ServletException {

// TODO Auto-generated method stub

}

@Override

public Collection<Part> getParts() throws IOException, ServletException {

// TODO Auto-generated method stub

return null;

}

@Override

public Part getPart(String name) throws IOException, ServletException {

// TODO Auto-generated method stub

return null;

}

@Override

public <T extends HttpUpgradeHandler> T upgrade(Class<T> httpUpgradeHandlerClass)

throws IOException, ServletException {

// TODO Auto-generated method stub

return null;

}

};

}

private static HttpServletResponse createResponse() {

return new HttpServletResponse() {

@Override

public String getCharacterEncoding() {

// TODO Auto-generated method stub

return null;

}

@Override

public String getContentType() {

// TODO Auto-generated method stub

return null;

}

@Override

public ServletOutputStream getOutputStream() throws IOException {

return null;

}

@Override

public PrintWriter getWriter() throws IOException {

// TODO Auto-generated method stub

return null;

}

@Override

public void setCharacterEncoding(String charset) {

// TODO Auto-generated method stub

}

@Override

public void setContentLength(int len) {

// TODO Auto-generated method stub

}

@Override

public void setContentLengthLong(long length) {

// TODO Auto-generated method stub

}

@Override

public void setContentType(String type) {

// TODO Auto-generated method stub

}

@Override

public void setBufferSize(int size) {

// TODO Auto-generated method stub

}

@Override

public int getBufferSize() {

// TODO Auto-generated method stub

return 0;

}

@Override

public void flushBuffer() throws IOException {

// TODO Auto-generated method stub

}

@Override

public void resetBuffer() {

// TODO Auto-generated method stub

}

@Override

public boolean isCommitted() {

// TODO Auto-generated method stub

return false;

}

@Override

public void reset() {

// TODO Auto-generated method stub

}

@Override

public void setLocale(Locale loc) {

// TODO Auto-generated method stub

}

@Override

public Locale getLocale() {

// TODO Auto-generated method stub

return null;

}

@Override

public void addCookie(Cookie cookie) {

// TODO Auto-generated method stub

}

@Override

public boolean containsHeader(String name) {

// TODO Auto-generated method stub

return false;

}

@Override

public String encodeURL(String url) {

// TODO Auto-generated method stub

return null;

}

@Override

public String encodeRedirectURL(String url) {

// TODO Auto-generated method stub

return null;

}

@Override

public String encodeUrl(String url) {

// TODO Auto-generated method stub

return null;

}

@Override

public String encodeRedirectUrl(String url) {

// TODO Auto-generated method stub

return null;

}

@Override

public void sendError(int sc, String msg) throws IOException {

// TODO Auto-generated method stub

}

@Override

public void sendError(int sc) throws IOException {

// TODO Auto-generated method stub

}

@Override

public void sendRedirect(String location) throws IOException {

// TODO Auto-generated method stub

}

@Override

public void setDateHeader(String name, long date) {

// TODO Auto-generated method stub

}

@Override

public void addDateHeader(String name, long date) {

// TODO Auto-generated method stub

}

@Override

public void setHeader(String name, String value) {

// TODO Auto-generated method stub

}

@Override

public void addHeader(String name, String value) {

// TODO Auto-generated method stub

}

@Override

public void setIntHeader(String name, int value) {

// TODO Auto-generated method stub

}

@Override

public void addIntHeader(String name, int value) {

// TODO Auto-generated method stub

}

@Override

public void setStatus(int sc) {

// TODO Auto-generated method stub

}

@Override

public void setStatus(int sc, String sm) {

// TODO Auto-generated method stub

}

@Override

public int getStatus() {

// TODO Auto-generated method stub

return 0;

}

@Override

public String getHeader(String name) {

// TODO Auto-generated method stub

return null;

}

@Override

public Collection<String> getHeaders(String name) {

// TODO Auto-generated method stub

return null;

}

@Override

public Collection<String> getHeaderNames() {

// TODO Auto-generated method stub

return null;

}

};

}

}

获取项目信息的工具类

package springboot.util;

import java.io.File;

import java.net.URL;

import java.net.URLClassLoader;

import java.util.HashMap;

import java.util.Map;

import java.util.Map.Entry;

import javax.servlet.Servlet;

/**

*

* 加载项目信息

*

* */

public class ProjectUtil {

public static Map<String,WebXml> load() throws Exception{

final Map<String,WebXml> projetInfo = new HashMap<String,WebXml>();

//j2ee定义的是tomcat下的webapp目录,本地我取自己打包的war包目录

String webapps = "E:\learning\SpringMVC\SpringMVC\webapps";

//读取tomcat发布的所有的项目

File[] projects = new File(webapps).listFiles(projectName -> projectName.isDirectory());

for(File project : projects) {

//根据每个项目的web.xml读取servlet信息

WebXml webXml = new XMLConfigUtil().load(project.getPath()+"\WEB-INF\web.xml");

webXml.projectPath = project.getPath();

//类加载,加载class文件-----war包或者jar包中解压的class文件

webXml.loadServlet();

projetInfo.put(project.getName(), webXml);

}

return projetInfo;

}

public class WebXml{

public String projectPath = null;

//查找项目中所有的servlet

public Map<String,Object> servlets = new HashMap<String,Object>();

public Map<String,Object> servletMapping = new HashMap<String,Object>();

//实例对象

public Map<String,Object> servletInstances = new HashMap<String,Object>();

public void loadServlet() throws Exception {

//jvm加载class文件

URL url = new URL("file:"+projectPath+"\WEB-INF\classes\");

URLClassLoader classLoader = new URLClassLoader(new URL[] {url});

//加载servlet,创建servlet对象

for(Entry<String,Object> entry : servlets.entrySet()) {

//servlet的名称

String servletName = entry.getKey();

//servlet类的完整路径

String servletClassName = entry.getValue().toString();

//加载

Class<?> clazz = classLoader.loadClass(servletClassName);

//反射创建对象,这就是为什么j2ee规范 servlet要继承HttpServlet,

Servlet servlet = (Servlet) clazz.newInstance();

this.servletInstances.put(servletName, servlet);

}

}

}

}

解析web.xml的工具类

package springboot.util;

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;

import javax.xml.parsers.SAXParser;

import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;

import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;

import springboot.util.ProjectUtil.WebXml;

public class XMLConfigUtil extends DefaultHandler {

// 查找项目中所有的servlet

public Map<String, Object> servlets = new HashMap<String, Object>();

public Map<String, Object> servletMapping = new HashMap<String, Object>();

// 实例对象

public Map<String, Object> servletInstances = new HashMap<String, Object>();

private String tag;// 存储操作的标签

private boolean isMapping = false;

private String currentServlet;

private String currentServletMapping;

public WebXml load(String path) throws SAXException, IOException, ParserConfigurationException {

// SAX解析

// 1、获取SAX解析工厂

SAXParserFactory factory = SAXParserFactory.newInstance();

// 2、从解析工厂中获取解析器

SAXParser parse = factory.newSAXParser();

XMLConfigUtil handler = new XMLConfigUtil();

// 5、解析

parse.parse(path, this);

// 6、获取数据

ProjectUtil.WebXml webXMl = new ProjectUtil().new WebXml();

webXMl.servlets = this.servlets;

webXMl.servletMapping = this.servletMapping;

return webXMl;

}

@Override

public void startDocument() throws SAXException {

}

@Override

public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

if (null != qName) {

tag = qName;// 存储标签名

if (tag.equals("servlet")) {

isMapping = false;

} else if (tag.equals("servlet-mapping")) {

isMapping = true;

}

}

}

@Override

public void characters(char[] ch, int start, int length) throws SAXException {

String contents = new String(ch, start, length).trim();

if (null != contents) {// 处理空的问题

if (isMapping) {// 操作servlet-mapping

if (tag.equals("servlet-name")) {

currentServletMapping = contents;

} else if (tag.equals("url-pattern")) {

String urlPattern = contents;

servletMapping.put(urlPattern, currentServlet);

}

} else {// 操作servlet

if (tag.equals("servlet-name")) {

currentServlet = contents;

currentServletMapping = contents;

} else if (tag.equals("servlet-class")) {

String servletClass = contents;

servlets.put(currentServlet, servletClass);

}

}

}

}

}

说明

本次代码没有实现request和response是的交互,返回都是写死的outputStream.write(“Hello World!”.getBytes())。

如果需要实现,需要写自己的request和response。

JAVA手写tomcat,带你了解tomcat的原理,附代码
声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>