實作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>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/546966.html
標籤:其他
下一篇:Java并發小結02
