前言
前面的文章,其实我们说过了。。回忆下 tomcat官网:https://tomcat.apache.org
The Apache Tomcat? software is an open source implementation of the Java Servlet,
JavaServer Pages, Java Expression Language and Java WebSocket technologies.
Tomcat 是使用了Java WebSocket技术和serlet技术,tomcat使用java实现
最核心的两部分connector和container connector部分,我们用bio的方式,websocket实现 container部分,用servlet集成 我们一步一步的说明
只实现web容器
新建一个maven项目叫my-tomcat
package com.my.tomcat.bio;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
public class Tomcat {
private static Logger logger= LoggerFactory.getLogger(Tomcat.class);
private static Properties pro = new Properties();
public static void init(){
try {
FileInputStream fileInputStream = new FileInputStream("src/main/resources/server.properties");
pro.load(fileInputStream);
logger.info("init 读取配置完成");
} catch (FileNotFoundException e) {
logger.error("初始化server配置文件错误",e.getMessage());
e.printStackTrace();
} catch (IOException e) {
logger.error("pro加载server报错",e.getMessage());
e.printStackTrace();
}
}
public static void start (){
int port = Integer.parseInt(pro.getProperty("server.port"));
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
while (true){
Socket accept = serverSocket.accept();
logger.info("收到连接请求.....");
OutputStream outputStream=accept.getOutputStream();
InputStream inputStream = accept.getInputStream();
dealInputStream(inputStream);
dealOutStream(outputStream,"success request");
}
} catch (IOException e) {
logger.error("启动tomcat报错",e.getMessage());
e.printStackTrace();
}finally {
if(null !=serverSocket)
{
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void dealInputStream(InputStream inputStream) throws IOException {
String httStr = "";
byte [] contentByte = new byte[1024];
int length;
if ((length = inputStream.read(contentByte)) >0){
httStr = new String(contentByte,0,length);
}
logger.info("访问请求内容为:"+httStr);
}
private static void dealOutStream(OutputStream outputStream, String outContent) throws IOException {
String httpResponse =
"HTTP/1.1 200 OK\n" +
"Content-Type: text/html\n" +
"\r\n" + outContent;
outputStream.write(httpResponse.getBytes());
outputStream.close();
}
public static void main(String[] args) {
init();
start();
}
}
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>org.example</groupId>
<artifactId>my-tomcat</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.11</java.version>
<build.sourceEncoding>UTF-8</build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
? Server.properties
server.port=8080
? 使用main方法启动
14:38:57.040 [main] INFO com.my.tomcat.bio.Tomcat - init 读取配置完成
? 结果
访问:http://localhost:8080/mytomcat?id=10 看看控制台打印:
14:45:15.590 [main] INFO com.my.tomcat.bio.Tomcat - 收到连接请求.....
14:45:15.612 [main] INFO com.my.tomcat.bio.Tomcat - 访问请求内容为:GET /mytomcat?id=10 HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
web容器+servlet
代码说明
? init方法中
1、servlet请求接口配置文件,嗯有请求接口配置了,那么得解析呀 2、servlet配置文件初始化并解析,结果放入内存中
? start方法中
先想到了什么呢? 1、请求过来后,是不是得有HttpServletRequest对象,ok,得有一个这个类,doGet,doPost,service方法 2、同样道理,有请求就有输出,得有HttpServletResponse类 3、那配置有了,请求处理有了,返回有了,缺个步骤啊,我怎么知道这个请求交给谁怎么去处理呀,OK,再来一个分发器,就组合起来了,我们一步一步来。。 4、那我们就要写请求的servlet,doGet,doPost,service方法,搞个抽象类呗
代码处理
代码结构
我们按照上面的步骤安排 ? init方法中servlet请求接口配置文件
server.port=8080
#servlet配置,不新建文件了
loginServlet.url=com.my.tomcat.bio.servlet.controller.LoginServlet:/login
helloServlet.url=com.my.tomcat.bio.servlet.controller.HelloServlet:/hello
package com.my.tomcat.bio.servlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
public class ServletMappingConfig {
public static List<ServletMapping> servletMappingList = new ArrayList<>();
public static Logger logger = LoggerFactory.getLogger(ServletMappingConfig.class);
public static void initServletMapping(Properties prop) {
Set<String> strings = prop.stringPropertyNames();
for (String str : strings) {
if (str.endsWith(".url")) {
String servletName = str.replaceAll(".url", "");
String value[] = prop.getProperty(str).split(":");
if (null == value || value.length != 2) {
logger.error("servlet配置异常--key=" + str + "--value=" + prop.getProperty(str));
logger.error("servlet请参考模板格式:servletName.url = ClassName:url");
continue;
}
ServletMapping servletInfo = new ServletMapping(servletName, value[0], value[1]);
logger.info("初始化servlet:" + servletInfo.toString());
servletMappingList.add(servletInfo);
}
}
}
}
package com.my.tomcat.bio.servlet;
public class ServletMapping {
private String servletName;
private String clazz;
private String url;
public ServletMapping(String servletName, String clazz, String url) {
this.servletName = servletName;
this.clazz = clazz;
this.url = url;
}
@Override
public String toString() {
return "ServletMapping{" +
"servletName='" + servletName + '\'' +
", clazz='" + clazz + '\'' +
", url='" + url + '\'' +
'}';
}
public String getServletName() {
return servletName;
}
public void setServletName(String servletName) {
this.servletName = servletName;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
? init方法中servlet配置文件初始化并解析,结果放入内存中
这个在Tomcat类中,最后再看
? start方法中的类
package com.my.tomcat.bio.servlet;
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);
}
}
}
package com.my.tomcat.bio.servlet;
import com.my.tomcat.bio.Tomcat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
public class HttpServletRequest {
private static Logger logger= LoggerFactory.getLogger(HttpServletRequest.class);
private String url;
private String method;
public HttpServletRequest(InputStream inputStream)throws IOException
{
String httStr = "";
byte [] contentByte = new byte[1024];
int length;
if ((length = inputStream.read(contentByte)) >0){
httStr = new String(contentByte,0,length);
}
logger.info("servlet访问请求内容为:"+httStr);
if (!httStr.isEmpty() && !httStr.equals("")) {
String httpHead = httStr.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;
}
}
package com.my.tomcat.bio.servlet;
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" +
"servlet响应"+
"\r\n" + content;
outputStream.write(httpResponse.getBytes());
outputStream.close();
}
}
? 请求controller servlet的类
package com.my.tomcat.bio.servlet.controller;
import com.my.tomcat.bio.servlet.HttpServletRequest;
import com.my.tomcat.bio.servlet.HttpServletResponse;
import com.my.tomcat.bio.servlet.Servlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class LoginServlet extends Servlet {
public static Logger logger = LoggerFactory.getLogger(LoginServlet.class);
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
logger.info("get method Login Servlet");
try {
response.write("login success");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
logger.info("post method Login Servlet");
try {
response.write("login success");
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.my.tomcat.bio.servlet.controller;
import com.my.tomcat.bio.servlet.HttpServletRequest;
import com.my.tomcat.bio.servlet.HttpServletResponse;
import com.my.tomcat.bio.servlet.Servlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class HelloServlet extends Servlet {
public static Logger logger = LoggerFactory.getLogger(LoginServlet.class);
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
logger.info("get method Hello Servlet");
try {
response.write("Hello success");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
logger.info("post method Hello Servlet");
try {
response.write("Hello success");
} catch (IOException e) {
e.printStackTrace();
}
}
}
? tomcatBio主启动类
package com.my.tomcat.bio;
import com.my.tomcat.bio.servlet.*;
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;
public class TomcatBio {
private static Logger logger = LoggerFactory.getLogger(TomcatBio.class);
private static Properties pro = new Properties();
private static Map<String, String> servletPool = new ConcurrentHashMap<>();
public static void init() {
try {
FileInputStream fileInputStream = new FileInputStream("src/main/resources/server.properties");
pro.load(fileInputStream);
logger.info("init 读取配置完成");
ServletMappingConfig.initServletMapping(pro);
for (ServletMapping servletMapping : ServletMappingConfig.servletMappingList) {
servletPool.put(servletMapping.getUrl(), servletMapping.getClazz());
}
logger.info("init servlet 配置完成");
} catch (FileNotFoundException e) {
logger.error("初始化server配置文件错误", e.getMessage());
e.printStackTrace();
} catch (IOException e) {
logger.error("pro加载server报错", e.getMessage());
e.printStackTrace();
}
}
public static void start() {
int port = Integer.parseInt(pro.getProperty("server.port"));
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
while (true) {
Socket accept = serverSocket.accept();
logger.info("收到连接请求.....");
OutputStream outputStream = accept.getOutputStream();
InputStream inputStream = accept.getInputStream();
HttpServletRequest httpServletRequest = new HttpServletRequest(inputStream);
HttpServletResponse httpServletResponse = new HttpServletResponse(outputStream);
dispatch(httpServletRequest,httpServletResponse);
logger.info("servlet请求完成.....");
}
} catch (IOException e) {
logger.error("启动tomcat报错", e.getMessage());
e.printStackTrace();
} finally {
if (null != serverSocket) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void dealInputStream(InputStream inputStream) throws IOException {
String httStr = "";
byte[] contentByte = new byte[1024];
int length;
if ((length = inputStream.read(contentByte)) > 0) {
httStr = new String(contentByte, 0, length);
}
logger.info("访问请求内容为:" + httStr);
}
private static void dealOutStream(OutputStream outputStream, String outContent) throws IOException {
String httpResponse =
"HTTP/1.1 200 OK\n" +
"Content-Type: text/html\n" +
"\r\n" + outContent;
outputStream.write(httpResponse.getBytes());
outputStream.close();
}
public static void dispatch(HttpServletRequest request, HttpServletResponse response) {
if (!servletPool.containsKey(request.getUrl())) {
logger.error("servlet分发器未找到对应的servlet的配置");
try {
String httpResponse =
"HTTP/1.1 200 OK\n" +
"Content-Type: text/html\n" +
"\r\n" + "404 Exception";
response.write(httpResponse);
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) {
init();
start();
}
}
验证
启动TomcatBio.java–>main()
17:45:27.718 [main] INFO com.my.tomcat.bio.TomcatBio - init 读取配置完成
17:45:27.774 [main] INFO com.my.tomcat.bio.servlet.ServletMappingConfig - 初始化servlet:ServletMapping{servletName='helloServlet', clazz='com.my.tomcat.bio.servlet.controller.HelloServlet', url='/hello'}
17:45:27.774 [main] INFO com.my.tomcat.bio.servlet.ServletMappingConfig - 初始化servlet:ServletMapping{servletName='loginServlet', clazz='com.my.tomcat.bio.servlet.controller.LoginServlet', url='/login'}
17:45:27.774 [main] INFO com.my.tomcat.bio.TomcatBio - init servlet 配置完成
访问:http://localhost:8080/mytomcat?id=10 结果:
访问:http://localhost:8080/login http://localhost:8080/hello
17:57:07.546 [main] INFO com.my.tomcat.bio.servlet.controller.LoginServlet - get method Login Servlet
17:57:07.548 [main] INFO com.my.tomcat.bio.TomcatBio - servlet请求完成.....
17:57:07.548 [main] INFO com.my.tomcat.bio.TomcatBio - 收到连接请求.....
17:57:12.447 [main] INFO com.my.tomcat.bio.servlet.controller.LoginServlet - get method Hello Servlet
17:57:12.448 [main] INFO com.my.tomcat.bio.TomcatBio - servlet请求完成.....
|