一、摘要:
序号 | 实现方式 | 功能链接 |
1 | BIO | 手写一个简化版的Tomcat(BIO版本) |
2 | BIO-Plus | 手写一个简化版的Tomcat(BIO升级版本) |
3 | NIO | 手写一个简化版的Tomcat(NIO版本) |
4 | Netty | 手写一个简化版的Tomcat(Netty版本) |
二、demo编码
package com.jason.http.server.bio;
import com.jason.http.server.support.servlet.ServletMapping;
import com.jason.http.server.support.servlet.ServletMappingConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import static java.lang.Thread.sleep;
public class Tomcat {
private static Logger logger= LoggerFactory.getLogger(Tomcat.class);
private static Properties prop=new Properties();
private static Map<String,String> servletPool=new ConcurrentHashMap<>();
public static void start()
{
int port=Integer.parseInt(prop.getProperty("server.port"));
logger.info("start tomcat finished , listen port at"+port);
logger.info("waiting request");
ServerSocket serverSocket=null;
try {
serverSocket=new ServerSocket(port);
while(true)
{
Socket accept = serverSocket.accept();
logger.info("收到连接请求.....");
try {
sleep(10000);//测试阻塞10秒,是否还可以响应其他请求,浏览器端观察效果
} catch (InterruptedException e) {
e.printStackTrace();
}
InputStream inputStream=accept.getInputStream();
OutputStream outputStream=accept.getOutputStream();
HttpServletRequest request=new HttpServletRequest(inputStream);
HttpServletResponse response=new HttpServletResponse(outputStream);
dispatch(request,response);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null !=serverSocket)
{
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void init() throws Exception
{
FileInputStream fin=new FileInputStream("F:\\workspace\\netty\\tomcat\\src\\main\\resources\\web-bio.properties");
prop.load(fin);
logger.info("读取配置");
ServletMappingConfig.initServletMapping(prop);
//解析servlet配置
for(ServletMapping servletMapping: ServletMappingConfig.servletMappingList)
{
servletPool.put(servletMapping.getUrl(),servletMapping.getClazz());
}
}
public static void dispatch(HttpServletRequest request, HttpServletResponse response)
{
if(!servletPool.containsKey(request.getUrl()))
{
logger.error("未找到对应的servlet的配置");
try {
response.write("404 Exception");
return ;
} catch (IOException e) {
e.printStackTrace();
}
}
String className=servletPool.get(request.getUrl());
try {
Class<Servlet> clazz=(Class<Servlet>)Class.forName(className);
Servlet servlet=clazz.newInstance();
servlet.service(request,response);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try{
init();
start();
}catch (Exception e)
{
e.printStackTrace();
}
}
}
public abstract class Servlet {
public static final String GET="GET";
public static final String PUT="POST";
public abstract void doGet(HttpServletRequest request, HttpServletResponse response);
public abstract void doPost(HttpServletRequest request, HttpServletResponse response);
public void service(HttpServletRequest request, HttpServletResponse response)
{
if(request == null)
{
System.out.println("HttpServletRequest is null");
}
if(response == null)
{
System.out.println("HttpServletResponse is null");
}
if(request.getMethod().equals("GET"))
{
doGet(request,response);
}else if(request.getMethod().equals("POST"))
{
doPost(request,response);
}
}
}
import java.io.IOException;
import java.io.OutputStream;
public class HttpServletResponse {
private OutputStream outputStream;
public HttpServletResponse(OutputStream outputStream)
{
this.outputStream=outputStream;
}
public void write(String content) throws IOException {
String httpResponse =
"HTTP/1.1 200 OK\n" +
"Content-Type: text/html\n" +
"\r\n" + content;
outputStream.write(httpResponse.getBytes());
outputStream.close();
}
}
import java.io.IOException;
import java.io.InputStream;
public class HttpServletRequest {
private String url;
private String method;
public HttpServletRequest(InputStream inputStream)throws IOException
{
String httpRequestStr="";
byte[] requestContent=new byte[1024];
int length;
if((length=inputStream.read(requestContent))>0)
{
httpRequestStr=new String(requestContent,0,length);
}
System.out.println(httpRequestStr);
String httpHead = httpRequestStr.split("\n")[0];
method = httpHead.split("\\s")[0];
url = httpHead.split("\\s")[1];
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
}
三、测试程序:
import com.jason.http.server.bio.HttpServletRequest;
import com.jason.http.server.bio.HttpServletResponse;
import com.jason.http.server.bio.Servlet;
import java.io.IOException;
public class HelloServlet extends Servlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
System.out.println("hello servlet");
try {
response.write("say hello world");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
System.out.println("hello servlet");
try {
response.write("say hello world");
} catch (IOException e) {
e.printStackTrace();
}
}
}
import com.jason.http.server.bio.HttpServletRequest;
import com.jason.http.server.bio.HttpServletResponse;
import com.jason.http.server.bio.Servlet;
import java.io.IOException;
public class LoginServlet extends Servlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
System.out.println("Login Servlet");
try {
response.write("login success");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
System.out.println("Login Servlet");
try {
response.write("login success");
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、配置文件:
1、web-bio.properties
server.port=8089
#格式:servletName.url=ClassName:url
loginServlet.url=com.jason.http.server.bio.demo.servlet.LoginServlet:/login
helloServlet.url=com.jason.http.server.bio.demo.servlet.HelloServlet:/hello
2、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.jason.http</groupId>
<artifactId>tomcat</artifactId>
<version>1.0-SNAPSHOT</version>
<name>tomcat</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.50.Final</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>