手写一个民用Tomcat (08)

这次我们Tomcat 的改动是  指责分离,同时引入一个Wrapper封装

我们的Processor 是负责处理处理请求的任务

我们的Connector 是负责通信的 

详细代码如下

public class JxdHttpConnector implements Runnable {int minProcessors = 3;int maxProcessors = 10;int curProcessors = 0;//存放多个processor的池子Deque<JxdHttpProcessor> processorDeque = new ArrayDeque<>();private  ServletContainer container;//sessions map存放sessionpublic static Map<String, HttpSession> sessions = new ConcurrentHashMap<>();//创建新的sessionpublic static JxdSession createSession() {JxdSession session = new JxdSession();session.setValid(true);session.setCreationTime(System.currentTimeMillis());String sessionId = generateSessionId();session.setId(sessionId);sessions.put(sessionId, session);return (session);}/*** 生成随机数方法* @return*/protected static synchronized String generateSessionId() {Random random = new Random();long seed = System.currentTimeMillis();random.setSeed(seed);byte bytes[] = new byte[16];random.nextBytes(bytes);StringBuffer result = new StringBuffer();for (int i = 0; i < bytes.length; i++) {byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);byte b2 = (byte) (bytes[i] & 0x0f);if (b1 < 10)result.append((char) ('0' + b1));elseresult.append((char) ('A' + (b1 - 10)));if (b2 < 10)result.append((char) ('0' + b2));elseresult.append((char) ('A' + (b2 - 10)));}return (result.toString());}@Overridepublic void run() {ServerSocket serverSocket = null;int port = 8080;try {serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));} catch (IOException e) {e.printStackTrace();System.exit(1);}//初始化池子 最开始三个initProcessorDeque();while (true) {Socket socket = null;try {//这是单线程 一个请求一个请求获取socketsocket = serverSocket.accept();//得到一个新的processor,这个processor从池中获取(池中有可能新建)JxdHttpProcessor processor = createProcessor();if (processor == null) {socket.close();continue;}processor.assign(socket);} catch (Exception e) {e.printStackTrace();}}}public void start() {Thread thread = new Thread(this);thread.start();}//从池子中获取一个processor,如果池子为空且小于最大限制,则新建一个private JxdHttpProcessor createProcessor() {synchronized (processorDeque) {if (processorDeque.size() > 0) {return processorDeque.pop();}if (curProcessors < maxProcessors) {return newProcessor();} else {return null;}}}private void initProcessorDeque() {for (int i = 0; i < minProcessors; i++) {JxdHttpProcessor processor = new JxdHttpProcessor(this);processor.start();processorDeque.push(processor);}curProcessors = minProcessors;}private JxdHttpProcessor newProcessor() {JxdHttpProcessor jxdHttpProcessor = new JxdHttpProcessor(this);jxdHttpProcessor.start();processorDeque.push(jxdHttpProcessor);curProcessors++;return processorDeque.pop();}public void recycle(JxdHttpProcessor processor) {processorDeque.push(processor);}public ServletContainer getContainer() {return container;}public void setContainer(ServletContainer container) {this.container = container;}
}

public class JxdHttpProcessor implements Runnable {boolean available = false;Socket socket;JxdHttpConnector connector;private int serverPort = 0;private boolean keepAlive = false;private boolean http11 = true;public JxdHttpProcessor(JxdHttpConnector connector) {this.connector = connector;}private void process(Socket socket) { //服务器循环等待请求并处理try {Thread.sleep(3000);} catch (InterruptedException e1) {e1.printStackTrace();}InputStream input = null;OutputStream output = null;// create Request object and parseJxdRequest request = new JxdRequest();try {output = socket.getOutputStream();keepAlive = true;//先关掉keepAlive 目前 为了方便测试
//            while (keepAlive) {request.parse(socket);// create Response objectJxdResponse response = new JxdResponse(output);response.setRequest(request);request.setResponse(response);//handle sessionif (request.getSessionId() == null || request.getSessionId().equals("")) {request.getSession(true);}response.setCharacterEncoding("UTF-8");response.addHeader(DefaultHeaders.CONTENT_TYPE_NAME, "text/html;charset=UTF-8");response.sendHeaders();//发送响应头//这段代码是测试用,可以获取的 请求参数 支持get 和postMap<String, String[]> map = request.getParameterMap();if (request.getUri().startsWith("/servlet/")) {//加载动态资源JxdServletProcessor jxdServletProcessor = new JxdServletProcessor(connector);jxdServletProcessor.process(request, response);} else {//加载静态资源StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor();staticResourceProcessor.process(request, response);}response.finishResponse();System.out.println("response header connection------"+response.getHeader("Connection"));if ("close".equals(response.getHeader("Connection"))) {keepAlive = false;}
//            }//因为是多线程所以只能交给httpProcessor 来关闭socket.close();} catch (Exception ea) {ea.printStackTrace();}}@Overridepublic void run() {while (true) {// 等待socket分配过来Socket socket = await();if (socket == null) continue;// 处理请求process(socket);// 回收processorconnector.recycle(this);}}public void start() {Thread thread = new Thread(this);thread.start();}private synchronized Socket await() {// 等待connector提供一个新的socketwhile (!available) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}// 获得这个新的SocketSocket socket = this.socket;//设置标志为falseavailable = false;//通知另外的线程notifyAll();return (socket);}public synchronized void assign(Socket socket) {// 等待connector提供一个新的socketwhile (available) {try {wait();} catch (InterruptedException e) {}}// 获取到这个新的Socketthis.socket = socket;// 把标志设置回去available = true;//通知另外的线程notifyAll();}
}

同时引入一个Wapper

/*** ServletContainer 主要用servletClsMap,servletInstanceMap 两个* map 管理Servlet*/
public class ServletWrapper {private Servlet instance = null;private String servletClass;private ClassLoader loader;private String name;protected ServletContainer container = null;public ServletWrapper(String servletClass, ServletContainer container) {this.container = container;this.servletClass = servletClass;try {loadServlet();} catch (ServletException e) {e.printStackTrace();}}public ClassLoader getLoader() {if (loader != null)return loader;return container.getLoader();}public Servlet getServlet(){return this.instance;}public Servlet loadServlet() throws ServletException {if (instance!=null) return instance;Servlet servlet = null;String actualClass = servletClass;if (actualClass == null) {throw new ServletException("servlet class has not been specified");}ClassLoader classLoader = getLoader();Class classClass = null;try {if (classLoader!=null) {classClass = classLoader.loadClass(actualClass);}}catch (ClassNotFoundException e) {throw new ServletException("Servlet class not found");}try {servlet = (Servlet) classClass.newInstance();}catch (Throwable e) {throw new ServletException("Failed to instantiate servlet");}try {servlet.init(null);}catch (Throwable f) {throw new ServletException("Failed initialize servlet.");}instance =servlet;return servlet;}public void invoke(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException {if (instance != null) {instance.service(request, response);}}
}

引入一个Servlet 容器 ,里边是一个map 用来管理 Servlet 不必每次都要创建

/*** ServletContainer 主要用servletClsMap,servletInstanceMap 两个* map 管理Servlet*/
public class ServletContainer {JxdHttpConnector connector = null;ClassLoader loader = null;//包含servlet类和实例的mapMap<String, String> servletClsMap = new ConcurrentHashMap<>(); //servletName -Map<String, ServletWrapper> servletInstanceMap = new ConcurrentHashMap<>();//servletNpublic ServletContainer() {try {
// create a URLClassLoaderURL[] urls = new URL[1];URLStreamHandler streamHandler = null;File classPath = new File(JxdHttpServer.WEB_ROOT);String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();urls[0] = new URL(null, repository, streamHandler);loader = new URLClassLoader(urls);} catch (IOException e) {System.out.println(e.toString());}}public String getInfo() {return null;}public ClassLoader getLoader() {return this.loader;}public void setLoader(ClassLoader loader) {this.loader = loader;}public JxdHttpConnector getConnector() {return connector;}public void setConnector(JxdHttpConnector connector) {this.connector = connector;}public String getName() {return null;}public void setName(String name) {}//invoke方法用于从map中找到相关的servlet,然后调用public void invoke(JxdRequest request, JxdResponse response) throws IOException, ServletException {ServletWrapper servletWrapper = null;String uri = request.getUri();//首先根据uri最后一个/号来定位,后面的字符串认为是servlet名字String servletName = uri.substring(uri.lastIndexOf("/") + 1);String servletClassName = servletName;servletWrapper = servletInstanceMap.get(servletName);//如果容器内没有这个servlet,先要load类,创建新实例if (servletWrapper == null) {servletWrapper = new ServletWrapper(servletClassName, this);this.servletClsMap.put(servletName, servletClassName);this.servletInstanceMap.put(servletName, servletWrapper);}try {HttpRequestFacade requestFacade = new HttpRequestFacade(request);HttpResponseFacade responseFacade = new HttpResponseFacade(response);System.out.println("Call service()");//让servletWrapper去执行servletservletWrapper.invoke(requestFacade,responseFacade);} catch (Exception e) {System.out.println(e.toString());} catch (Throwable e) {System.out.println(e.toString());}}
}

JxdHttpServer 我们的启动类 也发发生了变化
public class JxdHttpServer {public static final String WEB_ROOT = System.getProperty("user.dir");public static final String FILE_ROOT = "D:\\";public static void main(String[] args) {JxdHttpConnector connector = new JxdHttpConnector();ServletContainer container = new ServletContainer();connector.setContainer(container);container.setConnector(connector);connector.start();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/4623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue2多语言包i8n

1.下包(我是vue2) yarn add vue-i18n8.2.1 --save2.建多语言实例化文件 /* 多语言实例化文件*/ /* 1. 导入VueI18n和Vue 再去main.js中挂载插件*/ import Vue from vue // 引入Vue import VueI18n from vue-i18n // 引入国际化的包 // 2.引入cookie工具 import Cookie from …

wpf 按钮禁用样式

在WPF中&#xff0c;要为按钮创建一个禁用样式&#xff0c;需要在资源字典中定义一个Style&#xff0c;该样式将应用于Button控件的IsEnabled属性为False时的状态。 以下是一个简单的例子&#xff1a; <Style TargetType"Button" x:Key"NormalButtonStyle&…

虚良SEO的权重蜘蛛是真的吗?

权重蜘蛛&#xff0c;又称为搜索引擎蜘蛛或爬虫&#xff0c;是搜索引擎用来抓取和索引网页内容的重要工具。这些自动化程序在互联网上漫游&#xff0c;收集和分析信息&#xff0c;以帮助搜索引擎提供准确、相关和有用的搜索结果。权重蜘蛛的工作机制和特性对于理解搜索引擎优化…

jackson.dataformat.xml 反序列化 对象中包含泛型

重点&#xff1a; JacksonXmlProperty localName 指定本地名称 JacksonXmlRootElement localName 指定root的根路径的名称&#xff0c;默认值为类名 JsonIgnoreProperties(ignoreUnknown true) 这个注解写在类上&#xff0c;用来忽略在xml中有的属性但是在类中没有的情况 Jack…

边缘计算概述_5.边缘计算应用场景

1.智慧园区 智慧园区建设是利用新一代信息与通信技术来感知、监测、分析、控制、整合园区各个关键环节的资源&#xff0c;在此基础上实现对各种需求做出智慧的响应&#xff0c;使园区整体的运行具备自我组织、自我运行、自我优化的能力&#xff0c;为园区企业创建一个绿色、和谐…

python_django农产品物流信息服务系统6m344

Python 中存在众多的 Web 开发框架&#xff1a;Flask、Django、Tornado、Webpy、Web2py、Bottle、Pyramid、Zope2 等。近几年较为流行的&#xff0c;大概也就是 Flask 和 Django 了 Flask 是一个轻量级的 Web 框架&#xff0c;使用 Python 语言编写&#xff0c;较其他同类型框…

Eclipse C++ 无法debug 问题

环境&#xff1a; ubuntu20.04 Eclipse CDT&#xff08;x86_64) 工程&#xff0c;使用的是默认的CMake Project 现象&#xff1a; 1. 使用Eclipse&#xff0c; 加了断点后&#xff0c;debug 无法停在断点&#xff1b;step over 执行后是从main 直接执行到exit &#xff…

python爬取电影

这是一个简单的Python代码示例&#xff0c;使用requests和BeautifulSoup库来爬取电影信息。这个示例将从一个电影网站&#xff08;比如IMDb&#xff09;上抓取电影的标题。请注意&#xff0c;这个代码只是一个示例&#xff0c;并且网站的结构可能会发生变化&#xff0c;导致代码…

poi-tl自定义渲染策略学习

文章目录 实现逻辑参考代码注意点 实现逻辑 自定义渲染策略实现逻辑&#xff1a; 找到模板中的表格标签render方法接收java中对应模板表格标签的所有list数据执行自定义渲染逻辑 参考代码 word模板如下&#xff1a; 实体类&#xff1a; Data public class GksxRowData {/…

Linux多进程(二)进程通信方式三 共享内存

共享内存提供了一个在多个进程间共享数据的方式&#xff0c;它们可以直接访问同一块内存区域&#xff0c;因此比使用管道或消息队列等通信机制更高效。在多进程程序中&#xff0c;共享内存通常与信号量一起使用&#xff0c;以确保对共享内存的访问是线程安全的。 一、打开/创建…

07_for循环返回值while循环

文章目录 1.循环返回值2.yield接收for返回值3.scala调用yield方法创建线程对象4.scala中的while循环5.scala中的流程控制 1.循环返回值 for循环返回值是Unit 原因是防止产生歧义&#xff1b; 2.yield接收for返回值 // 2.yield关键字打破循环&#xff0c;可以使for循环输出…

webpack面试题(持续汇总ing。。。)

webpack的编译过程 初始化 此阶段&#xff0c;webpack会将CLI参数、配置文件、默认配置进行融合&#xff0c;形成一个最终的配置对象。对配置的处理过程是依托一个第三方库 yargs 完成的。此阶段相对比较简单&#xff0c;主要是为接下来的编译阶段做必要的准备目前&#xff0c;…

LLaMA 3:大模型之战的新序幕

作者 | 符尧 OneFlow编译 翻译&#xff5c;杨婷、宛子琳、张雪聃 本文要点概览&#xff1a; 文本数据的扩展可能已经达到了极限&#xff0c;因为易于获取的网络文本资源&#xff08;如Common Crawl、GitHub、ArXiv等&#xff09;已基本被充分利用。 尽管如此&#xff0c;通过更…

数据结构 - C/C++ - 数组

目录 结构特性 内存布局 结构样式 结构拓展 数据初始 元素访问 插入元素 删除元素 查找元素 修改元素 结构设计 成员变量 构造函数 功能函数 示例代码 结构特性 长度固定&#xff1a;数组的长度在创建时已经被确定&#xff0c;如果需要动态改变数组的长度&#…

C++面向对象程序设计 - 多继承,以及基类与派生类转换

单继承是一个类是从另一个基类派生类而来的&#xff0c;多继承则是一个派生类是同两个或多个基类&#xff0c;派生类从两人或多个基类中继承所需的属性。 声明多重继承的方法&#xff1a; class D: public A, private B, protected C { 类D新增加的成员 } 一、多重继承派生类的…

UI图中的opacity效果和代码效果不一样

有时UI图中使用了opacity属性&#xff0c;这个和前端代码效果不一致&#xff0c;修改方法&#xff1a; 不要用opacity属性&#xff0c;而是使用background:rgba( )的效果接客。

shell 局域网IP探活脚本

Linux Shell脚本是一种编程方式&#xff0c;它允许用户通过编写一系列命令和控制结构来自动化系统任务。Shell脚本通常以.sh为扩展名&#xff0c;使用诸如Bash、Zsh、Ksh等Shell解释器来执行。以下是一个简单的Shell脚本示例&#xff0c;该脚本用于展示如何遍历局域网的一个子网…

Vue---组件

Vue—组件 目录 Vue---组件定义组件全局组件局部组件 组件通讯***重点***父子通信之父传子&#xff08;props&#xff09;父子通信之子传父&#xff08;$emit&#xff09;ref属性&#xff08;$refs&#xff09; 动态组件插槽命名插槽 定义组件 全局组件 vue2中template只能传…

设置消息边界的方法有哪几种?

1. 特定字符或字符串 使用一些不会在正常消息内容中出现的特殊字符或字符串作为消息的分隔符。例如&#xff1a; 行分隔符&#xff1a;在类似于HTTP头部的文本协议中&#xff0c;可以使用换行符&#xff08;如\r\n&#xff09;作为每一行的结束标记。 特殊字符串&#xff1a;…

浏览器渲染机制:重排(Reflow)与重绘(Repaint)以及Vue优化策略

浏览器渲染机制是一个复杂但有序的过程&#xff0c;其目的是将HTML、CSS和JavaScript代码转化为用户可以看到和交互的视觉界面。重排&#xff08;Reflow&#xff09;与重绘&#xff08;Repaint&#xff09;是浏览器渲染过程中对页面元素进行更新的两个重要步骤&#xff0c;理解…