day04-实现SpringBoot底层机制
实现SpringBoot底层机制
Tomcat底层启动分析+Spring容器初始化+Tomcat关联Spring容器
1.任务1-创建Tomcat,并启动
(1)创建一个Maven项目,修改pom.xml文件:我们需要自己创建Tomcat对象,因此在引入的场景启动器中排除SpringBoot内嵌的Tomcat,并引入tomcat依赖库
<!--导入SpringBoot父工程-规定写法--> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.5.3</version> </parent> <dependencies> <!--导入web项目场景启动器:会自动导入和web开发相关的所有依赖[jar包]--> <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.指定版本为8.5.75 2.如果我们引入了自己指定的tomcat,一定要记住把前面的spring-boot-starter-tomcat排除 3.否则会出现GenericServletNotFound错误--> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>8.5.75</version> </dependency> </dependencies>
(2)创建LiSpringApplication.java
package com.li.lispringboot; import org.apache.catalina.startup.Tomcat; /** * @author 李 * @version 1.0 */ public class LiSpringApplication { //创建tomcat对象,并关联spring容器,然后启动tomcat public static void run() { try { //创建tomcat对象 Tomcat tomcat = new Tomcat(); //设置默认端口-9090 tomcat.setPort(9090); //启动,就会在指定端口监听 tomcat.start(); //等待请求接入 System.out.println("======9090端口等待请求接入======"); tomcat.getServer().await(); } catch (Exception e) { e.printStackTrace(); } } }
(3)LiMainApp
package com.li.lispringboot; /** * @author 李 * @version 1.0 */ public class LiMainApp { public static void main(String[] args) { //启动LiSpringBoot项目/程序 LiSpringApplication.run(); } }
(4)测试启动main方法,后台输出如下:


打开浏览器,访问9090端口,页面一片空白,因为这时候还没有接入其他组件。

2.任务2-创建Spring容器
(1)创建Monster.java,做一个测试bean
package com.li.lispringboot.bean; /** * @author 李 * @version 1.0 */ public class Monster { }
(2)创建HelloController.java,做一个测试Controller
package com.li.lispringboot.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author 李 * @version 1.0 */ @RestController public class HelloController { @RequestMapping("/hello") public String Hello() { return "Hello,I'm HelloController!"; } }
(3)创建LiConfig.java,作为Spring的配置文件
package com.li.lispringboot.config; import com.li.lispringboot.bean.Monster; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** * @author 李 * @version 1.0 * 配置类-作为Spring的配置文件 * 这里有一个问题,容器怎么知道要扫描哪些包? */ @Configuration @ComponentScan("com.li.lispringboot")//指定要配置类扫描哪些包 public class LiConfig { //注入Bean-Monster对象到Spring容器 @Bean public Monster monster() { return new Monster(); } }
(4)LiWebApplicationInitializer.java
package com.li.lispringboot; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; /** * @author 李 * @version 1.0 * LiWebApplicationInitializer容器初始化类的任务: * 1.创建spring容器 * 2.加载/关联spring容器的配置-按照注解方式 * 3.完成spring容器配置的bean的创建,依赖注入 * 4.创建前端控制器(DispatcherServlet),让其持有spring容器 * 5.这的onStartup()方法是tomcat来调用,并把ServletContext对象传入 */ public class LiWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { System.out.println("onStartup ..."); //加载-Spring Web Application Configuration AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); //在ac中注册配置类LiConfig ac.register(LiConfig.class); ac.refresh();//完成bean的创建和配置 /* 创建注册非常重要的前端控制器-DispatchServlet 让 DispatchServlet持有spring容器-ac 这样就可以进行映射分发 */ DispatcherServlet dispatcherServlet = new DispatcherServlet(ac); //返回ServletRegistration.Dynamic对象 ServletRegistration.Dynamic registration = servletContext.addServlet("app", dispatcherServlet); //设置前端控制器的加载顺序(这里设置为当tomcat启动时,就加载) registration.setLoadOnStartup(1); //设置前端控制器拦截所有请求,并进行分发处理 registration.addMapping("/"); } }
3.任务3-将Tomcat和Spring容器关联,并启动Spring容器
(1)修改LiSpringApplication,将tomcat和Spring容器关联
package com.li.lispringboot; import org.apache.catalina.startup.Tomcat; /** * @author 李 * @version 1.0 */ public class LiSpringApplication { //创建tomcat对象,并关联spring容器,然后启动tomcat public static void run() { try { //创建tomcat对象 Tomcat tomcat = new Tomcat(); /* 1.让tomcat能够将请求转发到SpringWeb容器,因此需要关联 2."/liboot" 就是我们的项目的 application context,即原来配置tomcat时的项目名称 3."D:\\IDEA-workspace\\li-springboot" 指定项目的路径 */ tomcat.addWebapp("/liboot", "D:\\IDEA-workspace\\li-springboot"); //设置默认端口-9090 tomcat.setPort(9090); //启动,就会在指定端口监听 tomcat.start(); //等待请求接入 System.out.println("======9090端口等待请求接入======"); tomcat.getServer().await(); } catch (Exception e) { e.printStackTrace(); } } }
(2)在LiMainApp.java中重新启动项目,在浏览器中访问测试Controller,访问成功:

3.1注意事项和细节
如果启动时报异常,如下:
严重: Servlet [jsp] in web application [/liboot] threw load() exception java.lang.ClassNotFoundException: org.apache.jasper.servlet.JspServlet
解决方案是:引入对应版本的 Jasper包即可。
<dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jasper</artifactId> <version>8.5.75</version> </dependency>
分类:
SpringBoot
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战