手写tomcat 加手写线程池结合

2024-09-03 02:58
文章标签 线程 tomcat 结合 手写

本文主要是介绍手写tomcat 加手写线程池结合,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

介绍:

前面的介绍copy别人的:

很多初学或将学java web的朋友总是被一系列异于常规java project的流程结构所困惑,搞不清事情的本质,这里就以最简单的方式来让初出茅庐的新手对java web项目有个清晰明了的认识。

java web的必定先行学过java基础,众所周知,java项目运行于一个public类中的一个pulblic static void main(String[])函数,然而java web中既没有了常规的main方法入口点同时各种纷乱的东西如jsp、html、tomcat以及servlet等也很容易让人陷入迷茫,就此使许多人在心中把java项目与web项目之间划起了天堑鸿沟。这里就带着这些问题看我给大家简单写上一个简单的“tomcat”来帮助初学者把java web与常规java项目统一起来,以利于朋友们在最初就能对java web项目有个较常规的认识。

首先,我们来研究下java web项目的运行过程。与普通java程序的main入口点不同,web似乎完全找不到了其入口点,然而需明确一点的是web项目中的servlet本身就是java类,同样是需要编译成.class被加载的,即使是jsp文件也是会经由jsp引擎转化为一个servlet被执行(html文件则仅被用来呆板的传输给双方浏览器解释)。所以web项目本质上还是一个java项目。那么它与传统java项目的差异又该作何解释?java项目根据程序流程触发,web项目则是基于网络访问事件触发,故本质上是一个事件驱动系统,然而任何事件驱动系统本身还是有一个确定的入口的,这点web也不例外。入口是有的,main也是有的,只是这些东西都被隐藏了起来,就是tomcat(亦或是其他web容器)的入口。这一点正如微软的MFC库封装了c++常规的main或WinMain入口一样,Tomcat也封装了java的main入口。

 下面我们就来动手写一个简单的tomcat仿真程序,此处必然绕不开java的反射机制(事实上所谓的Bean、控制反转、依赖注入等概念均离不开反射机制)。

1.首先我们来创建一个java项目Tomcat,创建一个Servlet.MyServletIn接口,添加一个service方法,以模拟servlet中的service方法。

2.将我们的Servlet.MyServletIn接口导出为ServletPkg.jar文件作为我们的servlet库。

3.在项目根目录下添加TomcatConf.txt文件作为Tomcat的配置文件,这里简单起见采用普通文本而非Xml文件,此文件中存放两行内容 ,第一行所要部署servlet项目目录,第二行你自己的真实Servlet类名(包含包路径)。

4.创建一个Core.TomcatCore类,并在其中添加main,作为整个容器的入口,在main中完成初始化tomcat本身、通过TomcatConf.txt配置文件下的servlet文件系统路径及类包路径信息,加载所部署servlet等工作。

5.另创建一个java项目MyWeb(此项目不需要main,用来模拟我们的web项目,当然这里只有servlet而已。)

6.将我们的”Servlet库“ServletPkg.jar导入我们的”Web项目“。

7.在MyWeb中添加一个实现了MyServletIn接口的类MyServlet。

8.实现MyServlet的抽象方法service模仿真实Servlet的行为。

9.部署我们的"web项目“到我们的Tomcat,即将我们的"web项目"根下的bin路径写入Tomcat根下的配置文件(TomcatConf.txt)的第一行,并将我们的Servlet类名写入配置文件第二行。如下:

F:\Users\smy\workspace-eclipse\MyServlet\bin
MyWeb.MyServlet

10.运行我们的"tomcat"。

下面是项目截图:

具体实现介绍:

package com.th.mytomcat;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicInteger;

Server :

public class Server {
static ServerSocket serverSocket;
static int port = 8080;


public Server(int port) {
this.port = port > 0 ? port : this.port;
}
static AtomicInteger socketCount = new AtomicInteger(0);

/**
 * 创建线程池 工作数量为1
 */
static ThreadPool<HttpRequestHandler> threadPool = new DefaultThreadPool<HttpRequestHandler>(1);

/**
 * tomcat容器启动方法
 */
public void start() throws Exception {
//异步加载WEB-INF文件 
new Thread(new Runnable() {
@Override
public void run() {
configUtils.initServlet("WEB-INF/web.xml");
}
}).start();

serverSocket = new ServerSocket(port);
System.out.println("MyTomcat START SUCCESS");
Socket socket = null;
while ((socket = serverSocket.accept()) != null) {
System.out.println("第" + socketCount.incrementAndGet() + "次连接.");
threadPool.execute(new HttpRequestHandler(socket));
}
}


/**
 * 判断是否静态资源 实际也应该在WEB-INF 进行静态文件的配置 这里简略的实现
 */
public static boolean isStatic(String uri) {
String[] suffixs = { "html", "css", "jpg", "js", "jpeg", "png" };
for (String suffix : suffixs) {
if (uri.endsWith("." + suffix)) {
return true;
}
}
return false;
}

/**
 * 判断String是否为空, return true 不为空,false 为空
 */
public static boolean IsEmpty(String str) {
if (str != null && str.trim().length() > 0)
return true;
return false;
}
}

 

Request:

package com.th.mytomcat;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;


public class Request {
private String uri;
/**
 * 获取请求的具体方法名称  未实现 作为保留
 */
private String method;
private HashMap<String, Object> parmMap = new HashMap<String, Object>();

/**
 * 获取请求传入的参数
 */
public Object getParmeter(String key) {
return parmMap.get(key);
}

public Request(InputStream inputStream) throws IOException {
byte[] buff = new byte[1024];
int len = inputStream.read(buff);
if (len > 0) {
String msg = new String(buff, 0, len);
// uri = msg.substring(msg.indexOf("/"), msg.indexOf("HTTP/1.1") - 1);

// 解析静态或者动态资源
int startIndex = msg.indexOf("POST") == -1 ? msg.indexOf("GET") + 4 : msg.indexOf("POST") + 5;
int endIndex = msg.indexOf("HTTP/1.1") - 1;
// 截取uri
uri = msg.substring(startIndex, endIndex);

String parmString = null;
if (msg.startsWith("GET")) {
System.out.println("GET方式请求的uri: " + uri);
} else if (msg.startsWith("POST")) {
// 获取POST参数
int paramStart = msg.lastIndexOf("\n");
parmString = msg.substring(paramStart + 1);
System.out.println("POST方式请求的表单参数: " + parmString);
// parmString = "userName=admin&pwd=123456"
if (parmString != null && !("".equals(parmString))) {
// 解析参数
if (parmString.contains("&")) {
String[] parms = parmString.split("&");
for (String parm : parms) {
parmMap.put(parm.split("=")[0], parm.split("=")[1]);
}
} else if (parmString.contains("=")) {
parmMap.put(parmString.split("=")[0], parmString.split("=")[1]);
}
}
}

} else {
System.out.println("bad request...");
}
}

public String getUri() {
return uri;
}
}

 

Response:

package com.th.mytomcat;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Response {
private OutputStream outputStream;

public Response(OutputStream outputStream) {
this.outputStream = outputStream;
}

/**
 * 响应静态文件
 */
public void writeFile(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
byte[] buff = new byte[1024];
int len = 0;
while ((len = fis.read(buff)) != -1) {
outputStream.write(buff, 0, len);
}
fis.close();
outputStream.flush();
outputStream.close();
}
}

 

HttpServlet类:

package com.th.mytomcat;
/**
 * Servlet原始基类
 */
public interface HttpServlet {
public void service(Request request, Response response) throws Exception;
}

 

LoginServlet:

package com.th.mytomcat;
public class LoginServlet implements HttpServlet{
@Override
public void service(Request request, Response response) throws Exception {
String userName = request.getParmeter("userName").toString();
String pwd = request.getParmeter("pwd").toString();

if(userName != null && userName.equals("admin") && pwd != null && pwd.equals("123")){
//跳转页面
System.out.println("login success");
response.writeFile("html/loginSuccess.html");
}else{
response.writeFile("html/error.html");
}
}
}

 

RegisterServlet :

package com.th.mytomcat;
public class RegisterServlet implements HttpServlet {
@Override
public void service(Request request, Response response) throws Exception {
response.writeFile("html/register.html");
}
}

 

HttpRequestHandler :

package com.th.mytomcat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;


public class HttpRequestHandler implements Runnable {
private Socket socket;

public HttpRequestHandler(Socket socket) {
this.socket = socket;
}

@Override
public void run() {
// 获取请求文件
try {
InputStream inputStream = socket.getInputStream();
Request request = new Request(inputStream);
String uri = request.getUri();

// 响应请求
OutputStream outputStream = socket.getOutputStream();
Response response = new Response(outputStream);

// 判断是否静态资源
if (Server.isStatic(uri)) {
response.writeFile(uri.substring(1));
} else if (uri.endsWith(".action")) {
// LoginServlet loginServlet = new LoginServlet();
// loginServlet.service(request, response);
for (Map.Entry<String, String> entry : configUtils.handlerMap.entrySet()) {
if (uri.endsWith(entry.getKey())) {
HttpServlet httpServlet = (HttpServlet) Class.forName(entry.getValue()).newInstance();
httpServlet.service(request, response);
}
}
}

} catch (Exception e) {
e.printStackTrace();
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

 

configUtils :

package com.th.mytomcat;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
 * @author th 解析web.xml 文件配置
 */
public class configUtils {
static Map<String, String> handlerMap = new HashMap<String, String>();

public static void initServlet(String path){
try {
getClassName(path);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("WEB-INF 文件加载完毕...");
}

private static Map<String, String> getClassName(String path) throws Exception {
// Map<String,String> handlerMap = new HashMap<String,String>();
SAXReader reader = new SAXReader();
File file = new File(path);
Document document = reader.read(file);
// 获取根元素
Element rootElement = document.getRootElement();
List<Element> childElements = rootElement.elements();
for (Element childElement : childElements) {
String key = childElement.element("url-pattern").getText();
String value = childElement.element("servlet-class").getText();
handlerMap.put(key, value);
}
return handlerMap;
}
}


ThreadPool:

package com.th.mytomcat;

public interface ThreadPool<Job extends Runnable> {
void execute(Job job);
void shutDown();
void addWorkers(int num);
void removeWorker(int num) throws Exception;
int getJosSize();
}

 

DefaultThreadPool:

package com.th.mytomcat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> {
// 最大线程数
private static final int MAX_WORKER_NUMBERS = 10;
// 默认线程数
private static final int DEFAULT_WORKER_NUMBERS = 5;
// 最小线程数
private static final int MIN_WORKER_NUMBERS = 1;
// 工作
private final LinkedList<Job> jobs = new LinkedList<Job>();
// 工作者
private final List<Worker> workers = (List<Worker>) Collections.synchronizedList(new ArrayList<Worker>());
// 实际工作现场数量
private int workerNum = DEFAULT_WORKER_NUMBERS;
// 线程编号
private AtomicLong threadNum = new AtomicLong();
public DefaultThreadPool() {
initializeWorkers(DEFAULT_WORKER_NUMBERS);
}

public DefaultThreadPool(int num) {
workerNum = num > MAX_WORKER_NUMBERS ? MAX_WORKER_NUMBERS : num < MIN_WORKER_NUMBERS ? MIN_WORKER_NUMBERS : num;
initializeWorkers(workerNum);
}

@Override
public void execute(Job job) {
if (job != null) {
synchronized (jobs) {
jobs.addLast(job);
jobs.notify();
}
}
}


@Override
public void shutDown() {
for (Worker worker : workers) {
worker.shutDown();
}
}

@Override
public void addWorkers(int num) {
synchronized (jobs) {
if (num + this.workerNum > MAX_WORKER_NUMBERS) {
num = MAX_WORKER_NUMBERS - this.workerNum;
}
initializeWorkers(num);
this.workerNum += num;
}
}

@Override
public void removeWorker(int num) throws Exception {
synchronized (jobs) {
if (num >= this.workerNum) {
throw new Exception("数量错误!");
}
int count = 0;
while (count < num) {
Worker worker = workers.get(count);
if (workers.remove(worker)) {
worker.shutDown();
count++;
}
}
this.workerNum -= count;
}
}

@Override
public int getJosSize() {
return jobs.size();
}

public void initializeWorkers(int num) {
for (int i = 0; i < num; i++) {
Worker worker = new Worker();
workers.add(worker);
Thread thread = new Thread(worker, "ThreadPool-Worker-" + threadNum.incrementAndGet());
thread.start();
}
}

class Worker implements Runnable {
// 继续工作的开关־
private volatile boolean running = true;


@Override
public void run() {
while (running) {
Job job = null;
synchronized (jobs) {
while (jobs.isEmpty()) {
try {
jobs.wait();
} catch (Exception e) {
Thread.currentThread().interrupt();
return;
}
}
job = jobs.removeFirst();
}
if (job != null) {
try {
job.run();
} catch (Exception e) {
}
}
}
}


public void shutDown() {
running = false;
}
}
}


index.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试页面</title>
</head>
<body>
<h1>第一张图片</h1>
<img src="../image/1.jpg" />

<!--  
<h1>第二张图片</h1>
<img src="../image/2.png" />

<h1>第三张图片</h1>
<img src="../image/3.png" />
-->
<form method="post" action="http://localhost:8080/login.action">
账号:<input type="text" name="userName">
密码<input type="password" name ="pwd">
<button type="submit">登录</button>
</form>
<a href="http://localhost:8080/register.action">注册</a>
</body>
</html>

开始运行 StartTomcat :

package com.th.mytomcat;
public class StartTomcat {

public static void main(String[] args) throws Exception {
Server server = new Server(8080);
server.start();
}
}

浏览器访问地址:http://localhost:8080/html/index.html

运行结果截图:

这篇关于手写tomcat 加手写线程池结合的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131827

相关文章

Python结合requests和Cheerio处理网页内容的操作步骤

《Python结合requests和Cheerio处理网页内容的操作步骤》Python因其简洁明了的语法和强大的库支持,成为了编写爬虫程序的首选语言之一,requests库是Python中用于发送HT... 目录一、前言二、环境搭建三、requests库的基本使用四、Cheerio库的基本使用五、结合req

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

最新版IDEA配置 Tomcat的详细过程

《最新版IDEA配置Tomcat的详细过程》本文介绍如何在IDEA中配置Tomcat服务器,并创建Web项目,首先检查Tomcat是否安装完成,然后在IDEA中创建Web项目并添加Web结构,接着,... 目录配置tomcat第一步,先给项目添加Web结构查看端口号配置tomcat    先检查自己的to

Apache Tomcat服务器版本号隐藏的几种方法

《ApacheTomcat服务器版本号隐藏的几种方法》本文主要介绍了ApacheTomcat服务器版本号隐藏的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需... 目录1. 隐藏HTTP响应头中的Server信息编辑 server.XML 文件2. 修China编程改错误

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

如何用Java结合经纬度位置计算目标点的日出日落时间详解

《如何用Java结合经纬度位置计算目标点的日出日落时间详解》这篇文章主详细讲解了如何基于目标点的经纬度计算日出日落时间,提供了在线API和Java库两种计算方法,并通过实际案例展示了其应用,需要的朋友... 目录前言一、应用示例1、天安门升旗时间2、湖南省日出日落信息二、Java日出日落计算1、在线API2

Java子线程无法获取Attributes的解决方法(最新推荐)

《Java子线程无法获取Attributes的解决方法(最新推荐)》在Java多线程编程中,子线程无法直接获取主线程设置的Attributes是一个常见问题,本文探讨了这一问题的原因,并提供了两种解决... 目录一、问题原因二、解决方案1. 直接传递数据2. 使用ThreadLocal(适用于线程独立数据)

若依部署Nginx和Tomcat全过程

《若依部署Nginx和Tomcat全过程》文章总结了两种部署方法:Nginx部署和Tomcat部署,Nginx部署包括打包、将dist文件拉到指定目录、配置nginx.conf等步骤,Tomcat部署... 目录Nginx部署后端部署Tomcat部署出现问题:点击刷新404总结Nginx部署第一步:打包

Nginx、Tomcat等项目部署问题以及解决流程

《Nginx、Tomcat等项目部署问题以及解决流程》本文总结了项目部署中常见的four类问题及其解决方法:Nginx未按预期显示结果、端口未开启、日志分析的重要性以及开发环境与生产环境运行结果不一致... 目录前言1. Nginx部署后未按预期显示结果1.1 查看Nginx的启动情况1.2 解决启动失败的

tomcat在nginx中的配置方式

《tomcat在nginx中的配置方式》文章介绍了如何在Linux系统上安装和配置Tomcat,并通过Nginx进行代理,首先,下载并解压Tomcat压缩包,然后启动Tomcat并查看日志,接着,配置... 目录一、下载安装tomcat二、启动tomcat三、配置nginx总结提示:文章写完后,目录可以自动