SpringBoot源碼篇:Spring5內置tomcat實現code-based的web.xml實現


一、簡介

  上篇文章講了SpingBoot誕生的歷史背景和技術演進背景,並通過源碼說明了SpringBoot是如何實現零配置的包括如何省去web.xml配置的原理。本文接上一篇文章,通過demo演示SpringBoot是如何內置tomcat並實現基於java配置的Servlet初始化和SpringBoot的啟動流程。

二、基於java配置的web.xml實現

傳統SpringMVC框架web.xml的配置內容

 1 <web-app>
 2     <!-- 初始化Spring上下文 -->
 3     <listener>
 4         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 5     </listener>
 6     <!-- 指定Spring的配置文件 -->
 7     <context-param>
 8         <param-name>contextConfigLocation</param-name>
 9         <param-value>/WEB-INF/app-context.xml</param-value>
10     </context-param>
11     <!-- 初始化DispatcherServlet -->
12     <servlet>
13         <servlet-name>app</servlet-name>
14         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
15         <init-param>
16             <param-name>contextConfigLocation</param-name>
17             <param-value></param-value>
18         </init-param>
19         <load-on-startup>1</load-on-startup>
20     </servlet>
21     <servlet-mapping>
22         <servlet-name>app</servlet-name>
23         <url-pattern>/app/*</url-pattern>
24     </servlet-mapping>
25 </web-app>

 

查看Spring官方文檔https://docs.spring.io/spring/docs/5.0.14.RELEASE/spring-framework-reference/web.html#spring-web

文檔中給出了如何使用java代碼實現web.xml配置的example

 1 public class MyWebApplicationInitializer implements WebApplicationInitializer {
 2 
 3     @Override
 4     public void onStartup(ServletContext servletCxt) {
 5 
 6         // Load Spring web application configuration
 7         //通過注解的方式初始化Spring的上下文
 8         AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
 9         //注冊spring的配置類(替代傳統項目中xml的configuration)
10         ac.register(AppConfig.class);
11         ac.refresh();
12 
13         // Create and register the DispatcherServlet
14         //基於java代碼的方式初始化DispatcherServlet
15         DispatcherServlet servlet = new DispatcherServlet(ac);
16         ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
17         registration.setLoadOnStartup(1);
18         registration.addMapping("/app/*");
19     }
20 }

 

通過example可見基於java的web.xml的實現

三、代碼實現簡易版SpringBoot

 1、工程目錄結構

2、pom.xml依賴

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <groupId>com.shf</groupId>
 6     <artifactId>spring-tomcat</artifactId>
 7     <version>0.0.1-SNAPSHOT</version>
 8     <name>spring-tomcat</name>
 9     <description>Demo project for Spring Boot</description>
10 
11     <properties>
12         <java.version>1.8</java.version>
13     </properties>
14 
15     <dependencies>
16         <dependency>
17             <groupId>org.springframework</groupId>
18             <artifactId>spring-web</artifactId>
19             <version>5.0.8.RELEASE</version>
20         </dependency>
21         <dependency>
22             <groupId>org.apache.tomcat.embed</groupId>
23             <artifactId>tomcat-embed-core</artifactId>
24             <version>8.5.32</version>
25         </dependency>
26         <dependency>
27             <groupId>org.springframework</groupId>
28             <artifactId>spring-context</artifactId>
29             <version>5.0.8.RELEASE</version>
30         </dependency>
31         <dependency>
32             <groupId>org.springframework</groupId>
33             <artifactId>spring-webmvc</artifactId>
34             <version>5.0.8.RELEASE</version>
35         </dependency>
36     </dependencies>
37 
38     <build>
39         <plugins>
40             <plugin>
41                 <groupId>org.springframework.boot</groupId>
42                 <artifactId>spring-boot-maven-plugin</artifactId>
43             </plugin>
44         </plugins>
45     </build>
46 
47 </project>

 

3、初始化tomcat實例

 1 package com.shf.tomcat.application;
 2 
 3 
 4 import org.apache.catalina.LifecycleException;
 5 import org.apache.catalina.startup.Tomcat;
 6 
 7 import javax.servlet.ServletException;
 8 
 9 /**
10  * 描述:初始化tomcat
11  *
12  * @Author shf
13  * @Date 2019/5/26 14:58
14  * @Version V1.0
15  **/
16 public class SpringApplication {
17     public static void run(){
18         //創建tomcat實例
19         Tomcat tomcat = new Tomcat();
20         //設置tomcat端口
21         tomcat.setPort(8000);
22         try {
23             //此處隨便指定一下webapp,讓tomcat知道這是一個web工程
24             tomcat.addWebapp("/", "D:\\");
25             //啟動tomcat
26             tomcat.start();
27             tomcat.getServer().await();
28         } catch (LifecycleException e) {
29             e.printStackTrace();
30         } catch (ServletException e) {
31             e.printStackTrace();
32         }
33     }
34 }

 

4、AppConfig.java

該類主要實現Spring的配置,基於java實現spring xml的配置

 1 package com.shf.tomcat.web;
 2 
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.context.annotation.Configuration;
 6 
 7 import javax.servlet.http.HttpServlet;
 8 
 9 /**
10  * 描述:java代碼實現類似於spring-context.xml的配置
11  *
12  * @Author shf
13  * @Date 2019/5/22 21:28
14  * @Version V1.0
15  **/
16 @Configuration
17 @ComponentScan("com.shf.tomcat")
18 public class AppConfig extends HttpServlet {
19     @Bean
20     public String string(){
21         return new String("hello");
22     }
23 }

 

5、MyWebApplicationInitializer.java

 值得一說,該類就是基於java的web.xml的配置

 1 package com.shf.tomcat.web;
 2 
 3 import org.springframework.web.WebApplicationInitializer;
 4 import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
 5 import org.springframework.web.servlet.DispatcherServlet;
 6 
 7 import javax.servlet.ServletContext;
 8 import javax.servlet.ServletException;
 9 import javax.servlet.ServletRegistration;
10 
11 /**
12  * 描述:WebApplicationInitializer實現web.xml的配置
13  *
14  * @Author shf
15  * @Date 2019/5/22 21:25
16  * @Version V1.0
17  **/
18 public class MyWebApplicationInitializer implements WebApplicationInitializer {
19     public void onStartup(ServletContext servletContext) throws ServletException {
20         System.out.println("初始化 MyWebApplicationInitializer");
21         //通過注解的方式初始化Spring的上下文
22         AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
23         //注冊spring的配置類(替代傳統項目中xml的configuration)
24         ac.register(AppConfig.class);
25 //        ac.refresh();
26 
27         // Create and register the DispatcherServlet
28         //基於java代碼的方式初始化DispatcherServlet
29         DispatcherServlet servlet = new DispatcherServlet(ac);
30         ServletRegistration.Dynamic registration = servletContext.addServlet("/", servlet);
31         registration.setLoadOnStartup(1);
32         registration.addMapping("/*");
33     }
34 }

 

6、MySpringServletContainerInitializer.java

該類上篇文章已經講的很清楚了

 1 package com.shf.tomcat.web;
 2 
 3 import org.springframework.core.annotation.AnnotationAwareOrderComparator;
 4 import org.springframework.util.ReflectionUtils;
 5 import org.springframework.web.WebApplicationInitializer;
 6 
 7 import javax.servlet.ServletContainerInitializer;
 8 import javax.servlet.ServletContext;
 9 import javax.servlet.ServletException;
10 import javax.servlet.annotation.HandlesTypes;
11 import java.lang.reflect.Modifier;
12 import java.util.LinkedList;
13 import java.util.List;
14 import java.util.Set;
15 
16 @HandlesTypes(MyWebApplicationInitializer.class)
17 public class MySpringServletContainerInitializer implements ServletContainerInitializer {
18     public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
19         List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
20 
21         if (webAppInitializerClasses != null) {
22             for (Class<?> waiClass : webAppInitializerClasses) {
23                 if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
24                         WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
25                     try {
26                         initializers.add((WebApplicationInitializer)
27                                 ReflectionUtils.accessibleConstructor(waiClass).newInstance());
28                     }
29                     catch (Throwable ex) {
30                         throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
31                     }
32                 }
33             }
34         }
35 
36         if (initializers.isEmpty()) {
37             servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
38             return;
39         }
40 
41         servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
42         AnnotationAwareOrderComparator.sort(initializers);
43         for (WebApplicationInitializer initializer : initializers) {
44             initializer.onStartup(servletContext);
45         }
46     }
47 }

 

 

7、META-INF/services/javax.servlet.ServletContainerInitializer

在該文件中配置ServletContainerInitializer的實現類

 

 

8、測試類

寫一個測試類

 1 package com.shf.tomcat.controller;
 2 
 3 import org.springframework.web.bind.annotation.RequestMapping;
 4 import org.springframework.web.bind.annotation.RestController;
 5 
 6 @RestController
 7 public class TestController {
 8     @RequestMapping("/app/test")
 9     public String test(){
10         System.out.println("--- hello ---");
11         return "hello";
12     }
13 }

 9、主類

 1 package com.shf.tomcat;
 2 
 3 
 4 import com.shf.tomcat.application.SpringApplication;
 5 
 6 public class Main {
 7 
 8     public static void main(String[] args) {
 9         SpringApplication.run();
10     }
11 
12 }

 

10、測試

啟動Main方法

瀏覽器訪問:http://localhost:8080/app/test

四、小結

  上篇文章介紹了SpringBoot是如何實現的基於java配置的web.xml。這篇文章我們通過一個demo來認識SpringBoot就是是如何內置tomcat並且實現零配置的。其實這個demo就像是一個簡易版的SpringBoot的框架,基本模擬了SpringBoot的啟動流程,只是差了SpringBoot最重要的能力---自動裝配。

  這兩篇文章嚴格來說不應該算是SpringBoot的源碼篇,但是筆者認為關於SpringBoot的發展歷史、技術演進路線、及SpringBoot的嵌入式tomcat和code-based web.xml配置也是認識SpringBoot重要的一部分。

  下一篇文章正式開始SpringBoot的源碼閱讀之旅。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM