实现SpringBoot底层机制[Tomcat启动分析 + Spring容器初始化 + Tomcat如何关联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语法
📚 目录导航 📚
- springboot系列一: springboot初步入门
- springboot系列二: sprintboot依赖管理
- springboot系列三: sprintboot自动配置
- springboot系列四: sprintboot容器功能
- springboot系列五: springboot底层机制实现 上
- springboot系列六: springboot底层机制实现 下
- springboot系列七: Lombok注解,Spring Initializr,yaml语法
…
💬 读者互动 💬
在探索 Spring Boot 底层机制的过程中,您有哪些新的发现或疑问?欢迎在评论区留言,让我们一起讨论吧!😊