实现SpringBoot底层机制
Tomcat底层启动分析+Spring容器初始化+Tomcat关联Spring容器
1.任务1-创建Tomcat,并启动
(1)创建一个Maven项目,修改pom.xml文件:我们需要自己创建Tomcat对象,因此在引入的场景启动器中排除SpringBoot内嵌的Tomcat,并引入tomcat依赖库- <parent>
- <artifactId>spring-boot-starter-parent</artifactId>
- <groupId>org.springframework.boot</groupId>
- <version>2.5.3</version>
- </parent>
- <dependencies>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
-
- <exclusions>
- <exclusion>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-tomcat</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
- <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>
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |