实现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容器@Beanpublic 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 {@Overridepublic void onStartup(ServletContext servletContext) throws ServletException {System.out.println("startup ...");//加载Spring web application configuration => 容器//自己实现的Spring容器叫做 ZzwSpringApplicationContextAnnotationConfigWebApplicationContext 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启动时,加载 dispatcherServletregistration.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 底层机制的过程中,您有哪些新的发现或疑问?欢迎在评论区留言,让我们一起讨论吧!😊