一、简介
上篇文章讲了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的源码阅读之旅。
来源:https://www.cnblogs.com/hello-shf/p/10952362.html