前面的文章,其实我们说过了。。回忆下
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集成
我们一步一步的说明
新建一个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;
/**
* 手写tomcat BIO模式
*/
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 (){
//启动web容器
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();
//先不使用servlet容器
//处理输入
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();
}
/**
* 启动main方法
* @param args
*/
public static void main(String[] args) {
init();
start();
}
}
pom.xml文件
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>my-tomcatartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<java.version>1.11java.version>
<build.sourceEncoding>UTF-8build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.5.6version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-pluginartifactId>
<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;
/**
* servlet配置解析
*/
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;
/**
* 解析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;
/**
* servlet请求处理
*/
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;
/**
* servlet response处理
*/
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;
/**
* 登录请求controller实现
*/
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;
/**
* hello servlet接口实现
*/
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;
/**
* 手写tomcat BIO模式
*/
public class TomcatBio {
private static Logger logger = LoggerFactory.getLogger(TomcatBio.class);
private static Properties pro = new Properties();
//servlet接口请求池
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 读取配置完成");
//初始化servlet配置
ServletMappingConfig.initServletMapping(pro);
//解析servlet配置,并放入请求池中
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() {
//启动web容器
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();
/* //先不使用servlet容器
//只使用web容器 处理输入
dealInputStream(inputStream);
//处理输出
dealOutStream(outputStream,"success request");*/
//使用servlet容器
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();
}
/**
* servlet分发器
* @param request 请求request
* @param response 请求response
*/
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();
}
}
/**
* 启动main方法
*
* @param args
*/
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请求完成.....
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)