springboot系列六: springboot底层机制实现 下

实现SpringBoot底层机制[Tomcat启动分析 + Spring容器初始化 + Tomcat如何关联Spring容器]

  • 实现任务阶段1-创建Tomcat, 并启动
    • 🥦说明:创建Tomcat, 并启动
    • 🥦分析+代码实现
    • 🥦完成测试
  • 实现任务阶段2-创建Spring容器
    • 🥦说明:创建Spring容器
    • 🥦分析+代码实现
  • 实现任务阶段3-将Tomcat 和 Spring容器关联, 并启动Spring容器
    • 🥦说明:将Tomcat 和 Spring容器关联, 并启动Spring容器
    • 🥦分析+代码实现
    • 🥦完成测试
    • 🥦注意事项和细节
    • 在这里插入图片描述

在这里插入图片描述


⬅️ 上一篇: springboot系列五: springboot底层机制实现 上


🎉 欢迎来到 springboot系列六: springboot底层机制实现 下 🎉

在本篇文章中,我们将继续深入探讨 Spring Boot 的底层机制。通过进一步理解这些底层机制,您可以更加全面地掌握 Spring Boot 的工作原理,并在实际项目中灵活运用。


🔧 本篇需要用到的项目: zzw-springboot项目


实现任务阶段1-创建Tomcat, 并启动

🥦说明:创建Tomcat, 并启动

🥦分析+代码实现

1.修改E:\idea_project\zzw_springboot\zzw-springboot\pom.xml

<!--导入web项目场景启动器: 会自动导入和web开发相关的所有依赖[库/jar]
后面还会说明spring-boot-starter-web 到底引入哪些相关依赖-->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!--
            因为我们自己要创建Tomcat对象, 并启动.
            因此我们先排除 内嵌的 spring-boot-starter-tomcat
        -->
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!--我们指定tomcat版本, 引入tomcat依赖/库

    1.使用指定的tomcat 8.5.75, 请小伙伴也引入这个版本
    2.如果我们引入自己指定的tomcat, 一定要记住把前面spring-boot-starter-tomcat排除
    3.如果你不排除, 会出现 GenericServlet Not Found 的错误提示.
    -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>8.5.75</version>
    </dependency>
</dependencies>

2.创建src/main/java/com/zzw/zzwspringboot/ZzwSpringApplication.java

public class ZzwSpringApplication {
    //这里我们会创建Tomcat对象, 并关联Spring容器, 并启动
    public static void run() {
        try {
            //创建Tomcat对象
            Tomcat tomcat = new Tomcat();
            //设置9090端口
            tomcat.setPort(9090);
            //启动, 就会在9090端口监听
            tomcat.start();
            //等待请求接入
            System.out.println("====9090 等待请求接入====");
            tomcat.getServer().await();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

3.主程序src/main/java/com/zzw/zzwspringboot/ZzwMainApp.java

//主程序
public class ZzwMainApp {
    public static void main(String[] args) {
        //启动ZzwSpringBoot项目/程序
        ZzwSpringApplication.run();
    }
}

🥦完成测试

1.运行效果
在这里插入图片描述

2.浏览器请求 http://localhost:9090/, 这时没有返回信息, 因为还没有写Controller.
在这里插入图片描述

3.管理员权限运行cmd窗口, 输入netstat -anb. 证明9090端口真的在监听.

在这里插入图片描述

实现任务阶段2-创建Spring容器

🥦说明:创建Spring容器

🥦分析+代码实现

1.新建src/main/java/com/zzw/zzwspringboot/bean/Monster.java, 做一个测试Bean

public class Monster {
}

2.新建src/main/java/com/zzw/zzwspringboot/controller/ZzwHiController.java, 作为Controller

@RestController
public class ZzwHiController {
    @RequestMapping("/hi")
    public String hi() {
        return "hi ZzwHiController";
    }
}

3.新建src/main/java/com/zzw/zzwspringboot/config/ZzwConfig.java, 作为Spring的配置文件

/**
 * ZzwConfig 配置类 作为Spring的配置文件
 * 这里有一个问题, 容器怎么知道要扫描哪些包 ?=> 一会代码体现
 *
 * 在配置类中可以指定要扫描的包: @ComponentScan("com.zzw.zzwspringboot")
 */
@Configuration
@ComponentScan("com.zzw.zzwspringboot")
public class ZzwConfig {
    //注入Bean - monster 对象到Spring容器
    @Bean
    public Monster monster() {
        return new Monster();
    }
}

4.新建src/main/java/com/zzw/zzwspringboot/ZzwWebApplicationInitializer.java

/**
 * 解读
 * 1.创建我们的Spring容器, Initializer-初始化器
 * 2.加载/关联Spring容器的配置-按照注解的方式
 * 3.完成Spring容器配置的bean的创建, 依赖注入
 * 4.创建前端控制器 DispatcherServlet, 并让其持有Spring容器
 * 5.当 DispatcherServlet 持有容器, 就可以进行分发映射, 回忆实现SpringMVC底层机制
 * 6.这里onStartup 是Tomcat调用, 并把ServletContext 对象传入
 */
public class ZzwWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        System.out.println("startup ...");

        //加载Spring web application configuration => 容器
        //自己实现的Spring容器叫做 ZzwSpringApplicationContext
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        //在ac中, 注册 ZzwConfig.class配置类
        ac.register(ZzwConfig.class);
        //刷新
        ac.refresh();//完成bean的创建和配置

        //1.创建注册非常重要的前端控制器 DispatcherServlet
        //2.让DispatcherServlet 持有容器
        //3.这样就可以进行映射分发, 回忆一下我们自己实现的SpringMVC的机制
        DispatcherServlet dispatcherServlet = new DispatcherServlet(ac);
        //返回了ServletRegistration.Dynamic 对象
        ServletRegistration.Dynamic registration
                = servletContext.addServlet("app", dispatcherServlet);
        //当tomcat启动时,加载 dispatcherServlet
        registration.setLoadOnStartup(1);
        //拦截请求, 并进行分发处理
        //这里再提示一下 / 和 /* 的区别
        registration.addMapping("/");
    }
}

实现任务阶段3-将Tomcat 和 Spring容器关联, 并启动Spring容器

🥦说明:将Tomcat 和 Spring容器关联, 并启动Spring容器

🥦分析+代码实现

1.修改src/main/java/com/zzw/zzwspringboot/ZzwSpringApplication.java

public class ZzwSpringApplication {
    //这里我们会创建Tomcat对象, 并关联Spring容器, 并启动
    public static void run() {
        try {
            //创建Tomcat对象
            Tomcat tomcat = new Tomcat();

            //1. 让tomcat可以将请求转发到spring web容器, 因此需要进行关联
            //2. "/zzwboot" 就是我们项目的 application context, 就是我们原来配置tomcat时, 指定的 application context
            //3. "E:\idea_project\zzw_springboot\zzw-springboot" 指定项目的目录
            tomcat.addWebapp("/zzwboot", "E:\\idea_project\\zzw_springboot\\zzw-springboot");

            //设置9090端口
            tomcat.setPort(9090);
            //启动, 就会在9090端口监听
            tomcat.start();
            //等待请求接入
            System.out.println("====9090 等待请求接入====");
            tomcat.getServer().await();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

2.debug运行一下, 这时会报错, 解决方案

在这里插入图片描述

refresh()负责注入初始化相关bean, 在未执行refresh方法前, spring容器是没有bean的

在这里插入图片描述

初始化后, 容器中有了bean文件

在这里插入图片描述

🥦完成测试

1.拿掉断点, 运行程序

2.浏览器请求 http://localhost:9090/zzwboot/hi
在这里插入图片描述

🥦注意事项和细节

1.如果启动包异常, 如下:
严重: Servlet [jsp] in web application [/zzwboot] threw load() exception
java.lang.ClassNotFoundException: org.apache.jasper.servlet.JspServlet

2.解决方案: 引入对应版本的jasper包即可, 修改E:\idea_project\zzw_springboot\zzw-springboot\pom.xml

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jasper</artifactId>
    <version>8.5.75</version>
</dependency>

在这里插入图片描述

🔜 下一篇预告: springboot系列七: Lombok注解,Spring Initializr,yaml语法


📚 目录导航 📚

  1. springboot系列一: springboot初步入门
  2. springboot系列二: sprintboot依赖管理
  3. springboot系列三: sprintboot自动配置
  4. springboot系列四: sprintboot容器功能
  5. springboot系列五: springboot底层机制实现 上
  6. springboot系列六: springboot底层机制实现 下
  7. springboot系列七: Lombok注解,Spring Initializr,yaml语法

💬 读者互动 💬
在探索 Spring Boot 底层机制的过程中,您有哪些新的发现或疑问?欢迎在评论区留言,让我们一起讨论吧!😊


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JAVA期末速成库(10)第十一章

一、习题介绍 Check Point&#xff1a;P416 11.1&#xff0c;11.6&#xff0c;11.7&#xff0c;11.8&#xff0c;11.12&#xff0c;11.17&#xff0c;11.24 Programming Exercise&#xff1a;11.1 二、习题及答案 Check Point&#xff1a; 11.1 True or false? A subcl…

elementUI的搭建使用过程

Element - The worlds most popular Vue UI framework 上面是elementUI的网站,进入网站 点击右上角的组件按钮 复制这段代码到你的项目终端:npm i element-ui -S 加载完成后即可使用elementUI网站中的组件,使用它们只需要复制组件下面的代码即可

Qt自定义信号

1.Teacher类下定义信号signals: Student类下定义槽函数&#xff1a; Teacher.h #pragma once#include <QObject>class Teacher : public QObject {Q_OBJECTpublic:Teacher(QObject *parent);~Teacher(); signals:void Ask(); //老师向学生提问void Ask(QString str);…

第3章_UART 开发基础

文章目录 第3章 UART 开发基础3.1 同步传输与异步传输3.1.1 概念与示例3.1.2 差别 3.2 UART 协议与操作方法3.2.1 UART 协议3.2.2 STM32H5 UART 硬件结构3.2.3 RS485 协议 3.3 UART 编程3.3.1 硬件连接3.3.2 三种编程方式3.3.3 查询方式3.3.4 中断方式3.3.5 DMA 方式 3.4 效率最…

「C++系列」C++简介、应用领域

文章目录 一、C简介C 的主要特点&#xff1a;C 的学习建议&#xff1a; 二、C 应用领域三、C 有哪些优势四、C 初学案例1. Hello, World!2. 两数求和3. 判断奇偶4. 判断闰年5. 判断质数6. 求阶乘7. 斐波那契数列8. 延时程序&#xff08;简单示例&#xff09; 五、相关链接 一、…

vue组件全局注册

描述&#xff1a; vue组件的注册分为局部和全局注册两部分&#xff0c;局部注册相对容易&#xff0c;不做赘述&#xff1b;而不同框架的注册方法又有所不同&#xff0c;下面针对vite框架和vue-cli框架的注册分别进行说明 vue组件全局注册 一、vite框架中全局组件注册二、Vue-cl…

点云入门知识

点云的处理任务 场景语义分割 物体的三维表达方法&#xff08;3D representations&#xff09;&#xff1a; 点云&#xff1a;是由物体表面上许多点数据来表征这个物体。最接近原始传感器数据&#xff0c;且具有丰富的几何信息。 Mesh&#xff1a;用三角形面片和正方形面片拼…

计算机语言vs指令vs中央处理器cpu

计算机中如何表示数据 在计算机中&#xff0c;所有数据和指令都是用二进制表示的&#xff0c;即0和1。这些0和1实际上是电压信号的高低电平&#xff0c;0通常表示低电平&#xff08;如0伏特&#xff09;&#xff0c;1表示高电平&#xff08;如5伏特&#xff09;。 指令系统&a…

食品行业怎么用JSON群发短信

食品作为日常生活不可缺少的元素&#xff0c;市场需求是很稳定的&#xff0c;但是份额就那么多&#xff0c;商家都要来抢占的话&#xff0c;就需要运营推广各凭本事&#xff0c;市场运营中选择合适的推广方式&#xff0c;可以增加店铺销售额&#xff0c;很多实体店或商城都会建…

LLM应用开发-RAG系统评估与优化

前言 Hello&#xff0c;大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者&#xff0c;在上一篇文章中&#xff0c;我们学习了如何基于LangChain构建RAG应用&#xff0c;并且通过Streamlit将这个RAG应用部署到了阿里云服务器&#xff1b;&am…

expandtabs()方法——tab符号转为空格

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 expandtabs()方法把字符串中的tab&#xff08;\t&#xff09;符号转为空格&#xff0c;tab&#xff08;\t&#xff09;符号默认的空格数是…

软考初级网络管理员__操作系统单选题

1.在Windows资源管理器中&#xff0c;假设已经选定文件&#xff0c;以下关于“复制”操作的叙述中&#xff0c;正确的有()。 按住Ctr键&#xff0c;拖至不同驱动器的图标上 按住AIt键&#xff0c;拖至不同驱动器的图标上 直接拖至不同驱动器的图标上 按住Shift键&#xff0…

普元EOS学习笔记-EOS8.3精简版安装

前言 普元EOS是优秀的高低开结合的企业应用软件开发框架。 普元&#xff1a;这是普元公司的名字&#xff0c;普元信息&#xff0c;上市公司哦&#xff0c;这里就不过多安利了。 EOS&#xff1a;普元公司的企业应用开发系统&#xff0c;开发语言是基于Java&#xff0c;技术框…

LLDP 基本原理

LLDP 简介 定义 LLDP&#xff08;Link Layer Discovery Protocol&#xff0c;链路层发现协议&#xff09;是 IEEE 802.1ab 中定义的第二层发现&#xff08;Layer 2 Discovery&#xff09;协议。 LLDP 提供了一种标准的链路层发现方式&#xff0c;可以将本端设备的主要能力、…

【51单片机入门】数码管原理

文章目录 前言共阴极与共阳极数码管多个数码管显示原理 总结 前言 在我们的日常生活中&#xff0c;数码管被广泛应用于各种电子设备中&#xff0c;如电子表、计时器、电子钟等。数码管的主要功能是显示数字和一些特殊字符。在这篇文章中&#xff0c;我们将探讨数码管的工作原理…

【详细】CNN中的卷积计算是什么-实例讲解

本文来自《老饼讲解-BP神经网络》https://www.bbbdata.com/ 目录 一、 CNN的基础卷积计算1.1.一个例子了解CNN的卷积计算是什么1.2.卷积层的生物意义 二、卷积的拓展&#xff1a;多输入通道与多输出通道2.1.多输入通道卷积2.2.多输出通道卷积 三、卷积的实现3.1.pytorch实现卷积…

助农扶贫网站

摘要&#xff1a;随着信息科技的快速发展和互联网的普及&#xff0c;信息技术在助力农业发展、促进农村振兴以及扶贫工作中发挥着越来越重要的作用。本文基于Spring Boot框架和Vue.js前端开发技术&#xff0c;设计完成了一个助农扶贫电商网站。网站提供便捷的农产品信息发布、农…

【验收支撑】项目验收计划书(Word原件)

软件验收相关的文档通常包括以下&#xff0c;这些文档在软件项目的不同阶段和验收过程中起着关键作用&#xff1a; 1、概要设计说明书&#xff1a; 描述了软件系统的整体架构、主要模块及其相互关系。 2、详细设计说明书&#xff1a; 提供了软件系统中各个模块的详细设计信息&a…

确保家电安全无忧:可燃气体报警器检验的重要性与必要性

随着家电行业的快速发展&#xff0c;安全问题已成为消费者关注的焦点。 可燃气体报警器作为一种重要的安全装置&#xff0c;在保障家庭安全中扮演着至关重要的角色。它能够实时监测室内可燃气体浓度&#xff0c;一旦超过预设的安全阈值&#xff0c;便会发出警报&#xff0c;提…

【Linux】服务器被work32病毒入侵CPU占用99%

文章目录 一、问题发现二、问题解决2.1 清楚病毒2.2 开启防火墙2.3 修改SSH端口2.4 仅使用凭据登录&#xff08;可选&#xff09; 一、问题发现 我的一台海外服务器&#xff0c;一直只运行一项服务&#xff08;你懂的&#xff09;&#xff0c;但是前不久我发现CPU占用99%。没在…