手写Spring之集成Tomcat与Servlet

  • 写在前面
  • 一、Web服务模型及servlet
    • 1.1 Web服务器
    • 1.2 请求流程
  • 二、实现
  • 三、小结

写在前面

最近学习了一下spring的相关内容,所以也就想要照猫画虎地记录和实现一下spring的框架,通过阅读这些也希望能够消除对Spring框架的恐惧,其实细心阅读框架也很容易理解。

这是手写Spring系列的第二篇文章,本篇文章将会对web容器对http请求的处理流程进行简答的介绍,然后具体介绍在mini-spring框架中集成tomcat容器的步骤,一步步完善我们的mini-spring框架。
在阅读这篇文章之前,希望你已经看过了上一篇我们对starter启动器的实现,然后继续集成tomcat到我们的mini-spring中。

项目的源码我放在了github上:源码地址

我会在这里整理文章的系列目录:

  1. 从头开始实现一个小型spring框架——手写Spring之实现SpringBoot启动
  2. 从头开始实现一个小型spring框架——手写Spring之集成Tomcat服务器
  3. 从头开始实现一个小型spring框架——控制器controller的实现
  4. 从头开始实现一个小型spring框架——实现Bean管理(IOC与DI)

一、Web服务模型及servlet

在正式实现之前我们需要了解tomcat服务器具体都做了哪些事情,了解web容器对数据的处理流程,才能够更好地吃透我们的min-spring框架。

1.1 Web服务器

  • 监听一个TCP端口,如tomcat默认监听的8080端口,浏览器默认的80端口。
    根据操作系统和计算机网络的相关知识,在传输层实现端到端的通信需要通过端口,每个端口又被应着的应用程序监听着,当有消息通过网络一层层寻址,找到相应ip下相应的端口,便把数据放到相应的端口,进而由应用程序解析相应的内容。
  • 转发请求,回复相应
  • 本身没有业务逻辑,仅负责连接操作系统和应用程序代码

1.2 请求流程

客户端从浏览器发出请求,通过网络将数据bit流传输至Web服务器(细节方面涉及计算机网络的分层模型和数据传输过程,这里不过多介绍),其中还包含了数据请求的端口以及定义的各种协议信息,网卡拿到网络中传来的bit流,将数据转换为字节流,并交给相应的端口处理(本篇采用的是8899端口)。而我们的web容器如tomcat,就在监听着这些端口,并将传来的请求移交给相应的代码处理,随时处理网络中传来的数据。但具体处理方式对于web容器来说是一个黑盒容器并不关系具体的处理过程是怎样的,他只负责接收请求和发回相应两件事情。

二、实现

要在mini-spring项目中集成我们的tomcat,首先需要在gradle中添加相应的依赖。

framework的build.gradle中的dependences添加tomcat的embed版本的相关依赖(因为只是简单实现,所以选择这个版本)
包结构(web包下增加server包和servlet包)

我们需要在framework的依赖中添加这么一段:

// https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-corecompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.5.23'

整体的代码

plugins {id 'java'
}group 'com.qcby'
version '1.0-SNAPSHOT'sourceCompatibility = 1.8repositories {mavenCentral()
}dependencies {testCompile group: 'junit', name: 'junit', version: '4.12'// https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-corecompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.5.23'
}

在web包下新建一个server包用于保存容器相关的代码

新建TomcatServer类用于实现我们的Tomcat

package com.qcby.web.server;import com.qcby.web.servlet.TestServlet;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;/*** @author kevinlyz* @ClassName TomcatServer* @Description 集成Tomcat服务器* @Date 2019-06-05 13:10**/
public class TomcatServer {private Tomcat tomcat;private String[] agrs;public TomcatServer(String[] agrs) {this.agrs = agrs;}public void startServer() throws LifecycleException {//实例化tomcattomcat = new Tomcat();tomcat.setPort(8899);tomcat.start();//实例化context容器Context context = new StandardContext();context.setPath("");context.addLifecycleListener(new Tomcat.FixContextListener());TestServlet testServlet = new TestServlet();Tomcat.addServlet(context,"testServlet",testServlet).setAsyncSupported(true);//添加URL映射context.addServletMappingDecoded("/test.json","testServlet");tomcat.getHost().addChild(context);//设置守护线程防止tomcat中途退出Thread awaitThread = new Thread("tomcat_await_thread."){@Overridepublic void run() {TomcatServer.this.tomcat.getServer().await();}};//设置为非守护线程awaitThread.setDaemon(false);awaitThread.start();}
}

servlet包下新建TestServlet用于响应请求

package com.qcby.web.servlet;import javax.servlet.*;
import java.io.IOException;/*** @author kevinlyz* @ClassName TestServlet* @Description * @Date 2019-06-05 13:28**/
public class TestServlet implements Servlet {@Overridepublic void init(ServletConfig config) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {res.getWriter().write("test");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}

最后在MiniApplication中实例化我们的Tomcat容器

package com.qcby.starter;import com.qcby.web.server.TomcatServer;
import org.apache.catalina.LifecycleException;/*** @author kevinlyz* @ClassName MiniApplication* @Description 框架的入口类* @Date 2019-06-04 19:21**/
public class MiniApplication {public static void run(Class<?> cls,String[] args){System.out.println("Hello mini-spring application!");TomcatServer tomcatServer = new TomcatServer(args);try {tomcatServer.startServer();} catch (LifecycleException e) {e.printStackTrace();}}
}

然后gradle build

输入命令:java -jar test/build/libs/test-1.0-SNAPSHOT.jar
看到控制台打印8899端口的启动

打开浏览器

看到response返回的test字符串!

喜大普奔,大功告成!

三、小结

这是手写Spring系列的第二篇文章,本篇文章在第一篇实现SpringBoot启动的基础上进一步将Tomcat容器集成在了我们的mini-spring框架中。首先对容器处理请求的逻辑进行了简单介绍,分析了tomcat容器对请求的处理和响应,对于内部数据究竟是怎样处理的,web容器并不关心。然后对tomcat的集成做了具体实现,我们新添加了TomcatServer和TestServlet类分别实例化我们的容器和测试我们的Servlet请求拦截,当TestServlet正确匹配到我们请求的/test.json,并成功返回一个test字符串,说明我们的Servelt是有效的。

P.S. 在TomcatServer实例化容器的时候,我们设置了一个守护线程,以防止容器的中途退出

从头开始实现一个小型spring框架——手写Spring之集成Tomcat服务器相关推荐

  1. JAVA项目代码手写吗_一个老程序员是如何手写Spring MVC的

    见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十多 ...

  2. 05. 手写Spring核心框架

    目录 05 手写Spring核心框架 Pt1 手写IoC/DI Pt1.1 流程设计 Pt1.2 基础配置 application.properties pom.xml web.xml Pt1.3 注 ...

  3. 手把手教你手写Spring框架

    手写spring准备工作: 新建一个maven工程: 架构 新建类: package com.spring;public class keweiqinApplicationContext {priva ...

  4. 记录一次阿里架构师全程手写Spring MVC

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

  5. 十年java架构师分享:我是这样手写Spring的

    人见人爱的 Spring 已然不仅仅只是一个框架了.如今,Spring 已然成为了一个生态.但深入了解 Spring 的却寥寥无几.这里,我带大家一起来看看,我是如何手写 Spring 的.我将结合对 ...

  6. 手写 Spring 事务、IOC、DI 和 MVC

    Spring AOP 原理 什么是 AOP? AOP 即面向切面编程,利用 AOP 可以对业务进行解耦,提高重用性,提高开发效率 应用场景:日志记录,性能统计,安全控制,事务处理,异常处理 AOP 底 ...

  7. 【Spring框架一】——Spring框架简介

    系列文章目录 Spring框架简介 系列文章目录 前言 一.什么是Spring框架? 二.Spring框架的优势 1.简化开发流程:Spring提供了许多现成的功能,可以使得开发人员在构建应用程序时减 ...

  8. 手写Spring DI依赖注入,嘿,你的益达!

    手写DI 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBean ...

  9. 手写 Spring MVC

    学习自<Spring 5核心原理与30个类手写实战>作者 Tom 老师 手写 Spring MVC 不多说,简历装 X 必备.不过练好还是需要求一定的思维能力. 一.整体思路 思路要熟练背 ...

最新文章

  1. datatable 导入mysql 解决_将DataTable中的数据导入到数据库中
  2. python爬取糗事百科
  3. 阅读《Google成功七堂课》
  4. python length-1_TypeError:使用基本操作时,只有length1数组可以转换为Python标量
  5. Eclipse 中 Could not find *.apk的解决方案
  6. 大学英语计算机开学考试试题,2018年全国大学英语四级考试阅读理解试题:学习计算机...
  7. 使用容器和Elasticsearch集群对Twitter进行监控
  8. IntelliJ IDEA 使用教程(2019图文版)
  9. 小程序pdf预览插件_微信小程序中预览 PDF 文档
  10. python sep参数_Python sep参数使用方法详解
  11. 成为软件架构师需要什么?
  12. JavaScript 计算地下城堡2资源何时满仓
  13. arduino步进电机程序库_Arduino入门教程15(步进电机驱动库的使用):Arduino Uno R3+ULN2003+步进电机 使用Stepper驱动库,控制步进电机转动角度...
  14. TKeed源码解析之URI解析
  15. 重大利好,区块链技术能保护森林资源?
  16. 好听的名字 - 收藏给宝宝起名字用
  17. 互联网电视无处不在的广告惹人烦,消费者转投传统电视怀抱
  18. 965年10元纸币收藏价值
  19. 微型计算机用的是直流电吗,皮卡丘用的是直流电还是交流电?⚡️⚡️
  20. office2016和office visio2016同时安装包你一次成功

热门文章

  1. 数据库-差集交集并集
  2. 怎么添加、修改或删除快递单号
  3. Java 开源中文分词器Ansj 学习教程
  4. 淘宝官方订单API接口,获取售出的商品订单列表(爬虫数据)
  5. Visual Studio “另一个安装程序已开始运行。请先等它完成,然后再重试”和“正在进行其他安装,请稍后重试...”解决方法
  6. 怎么样在腾讯云服务器桌面环境安装
  7. 代数一千二百年:花拉子米和智慧宫 ︱ 尼克
  8. 神舟k610d i7 d2 黑苹果安装资源 10.15.x
  9. 设计模式六大原则(初步理解)
  10. web渗透--60--本地存储安全