SpringBoot源码篇:Spring5内置tomcat实现code-based的web.xml实现
一、简介
上篇文章讲了SpingBoot诞生的历史背景和技术演进背景,并通过源码说明了SpringBoot是如何实现零配置的包括如何省去web.xml配置的原理。本文接上一篇文章,通过demo演示SpringBoot是如何内置tomcat并实现基于java配置的Servlet初始化和SpringBoot的启动流程。
二、基于java配置的web.xml实现
传统SpringMVC框架web.xml的配置内容
<web-app>
<!-- 初始化Spring上下文 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 指定Spring的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<!-- 初始化DispatcherServlet -->
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
查看Spring官方文档https://docs.spring.io/spring/docs/5.0.14.RELEASE/spring-framework-reference/web.html#spring-web
文档中给出了如何使用java代码实现web.xml配置的example
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
//通过注解的方式初始化Spring的上下文
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//注册spring的配置类(替代传统项目中xml的configuration)
ac.register(AppConfig.class);
ac.refresh();
// Create and register the DispatcherServlet
//基于java代码的方式初始化DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
通过example可见基于java的web.xml的实现
三、代码实现简易版SpringBoot
1、工程目录结构

2、pom.xml依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shf</groupId>
<artifactId>spring-tomcat</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-tomcat</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
3、初始化tomcat实例
package com.shf.tomcat.application; import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat; import javax.servlet.ServletException; /**
* 描述:初始化tomcat
*
* @Author shf
* @Date 2019/5/26 14:58
* @Version V1.0
**/
public class SpringApplication {
public static void run(){
//创建tomcat实例
Tomcat tomcat = new Tomcat();
//设置tomcat端口
tomcat.setPort(8000);
try {
//此处随便指定一下webapp,让tomcat知道这是一个web工程
tomcat.addWebapp("/", "D:\\");
//启动tomcat
tomcat.start();
tomcat.getServer().await();
} catch (LifecycleException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
}
}
4、AppConfig.java
该类主要实现Spring的配置,基于java实现spring xml的配置
package com.shf.tomcat.web; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import javax.servlet.http.HttpServlet; /**
* 描述:java代码实现类似于spring-context.xml的配置
*
* @Author shf
* @Date 2019/5/22 21:28
* @Version V1.0
**/
@Configuration
@ComponentScan("com.shf.tomcat")
public class AppConfig extends HttpServlet {
@Bean
public String string(){
return new String("hello");
}
}
5、MyWebApplicationInitializer.java
值得一说,该类就是基于java的web.xml的配置
package com.shf.tomcat.web; 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; /**
* 描述:WebApplicationInitializer实现web.xml的配置
*
* @Author shf
* @Date 2019/5/22 21:25
* @Version V1.0
**/
public class MyWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("初始化 MyWebApplicationInitializer");
//通过注解的方式初始化Spring的上下文
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//注册spring的配置类(替代传统项目中xml的configuration)
ac.register(AppConfig.class);
// ac.refresh(); // Create and register the DispatcherServlet
//基于java代码的方式初始化DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletContext.addServlet("/", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
}
}
6、MySpringServletContainerInitializer.java
该类上篇文章已经讲的很清楚了
package com.shf.tomcat.web; import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.WebApplicationInitializer; import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;
import java.util.Set; @HandlesTypes(MyWebApplicationInitializer.class)
public class MySpringServletContainerInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>(); if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
} if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
} servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
7、META-INF/services/javax.servlet.ServletContainerInitializer

在该文件中配置ServletContainerInitializer的实现类

8、测试类
写一个测试类
package com.shf.tomcat.controller; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public class TestController {
@RequestMapping("/app/test")
public String test(){
System.out.println("--- hello ---");
return "hello";
}
}
9、主类
package com.shf.tomcat;
import com.shf.tomcat.application.SpringApplication;
public class Main {
public static void main(String[] args) {
SpringApplication.run();
}
}
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的源码阅读之旅。
SpringBoot源码篇:Spring5内置tomcat实现code-based的web.xml实现的更多相关文章
- springboot源码之(内嵌tomcat)
server---service----engine----host-----context---wrapper---servletStandardServer---StandardService-- ...
- SpringBoot源码篇:深度分析SpringBoot如何省去web.xml
一.前言 从本博文开始,正式开启Spring及SpringBoot源码分析之旅.这可能是一个漫长的过程,因为本人之前阅读源码都是很片面的,对Spring源码没有一个系统的认识.从本文开始我会持续更新, ...
- springboot学习笔记:6.内置tomcat启动和外部tomcat部署总结
springboot的web项目的启动主要分为: 一.使用内置tomcat启动 启动方式: 1.IDEA中main函数启动 2.mvn springboot-run 命令 3.java -jar XX ...
- Vue源码后记-其余内置指令(1)
把其余的内置指令也搞完吧,来一个全家桶. 案例如下: <body> <div id='app'> <div v-if="vIfIter" v-bind ...
- Vue源码后记-其余内置指令(2)
-- 指令这个讲起来还有点复杂,先把html弄上来: <body> <div id='app'> <div v-if="vIfIter" v-bind ...
- Vue源码后记-其余内置指令(3)
其实吧,写这些后记我才真正了解到vue源码的精髓,之前的跑源码跟闹着玩一样. go! 之前将AST转换成了render函数,跳出来后,由于仍是字符串,所以调用了makeFunction将其转换成了真正 ...
- 10.源码分析---SOFARPC内置链路追踪SOFATRACER是怎么做的?
SOFARPC源码解析系列: 1. 源码分析---SOFARPC可扩展的机制SPI 2. 源码分析---SOFARPC客户端服务引用 3. 源码分析---SOFARPC客户端服务调用 4. 源码分析- ...
- android studio应用修改到android源码中作为内置应用
1. 方法一:导入,编译(太麻烦,各种不兼容问题) android studio和eclipse的应用结构目录是不同的,但是在android源码中的应用基本上都是使用的eclipse目录结构(在/pa ...
- 不是springboot项目怎么使用内置tomcat
不是springboot项目怎么使用内置tomcat 解决方法: 1.pom.xml中添加以下依赖 <properties> <tomcat.version>8.5.23 ...
随机推荐
- DBCP2的使用例子和源码详解(不包括JNDI和JTA支持的使用)
目录 简介 使用例子 需求 工程环境 主要步骤 创建项目 引入依赖 编写jdbc.prperties 获取连接池和获取连接 编写测试类 配置文件详解 数据库连接参数 连接池数据基本参数 连接检查参数 ...
- IDEA的控制台拖拽出来之后,如何恢复?
大家搜到这个的时候,肯定遇到了如下图展示的尴尬情况,我们的控制台在不小心之间被拖拽出来,然后不知如何再拖回去?放心,我来告诉你怎么办. 点击左下角的 恢复按钮 就可以了.
- Java语法进阶12-集合
集合 集合:是一种容器,用来装对象的容器,不能装基本数据类型. 数组也是容器,可以用来装基本数据类型,也可以用来装对象. 本质上,集合需要用对应的数据结构实现,是多个类实现接口Collection系列 ...
- css练习一
总体的html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF- ...
- make命令和makefile
make命令和Makefiles: 1. make是一个命令,解释makefile中指令的命令工具,不同的IDE有自己的make命令. 1. make命令不知道怎么去构建程序,必须有一个文件告诉mak ...
- windows下利用iis建立网站网站并实现局域共享
博客园 首页 新随笔 联系 管理 订阅 随笔- 54 文章- 9 评论- 0 Windows下利用IIS建立网站并实现局域网共享 https://blog.csdn.net/qq_4148541 ...
- OA项目之mybatis动态查询
类似于三个条件,可以全部选择,也可以选择几个条件进行查询 Mapper.xml文件: <resultMap type="Employee" id="selAll&q ...
- poj3111 K Best 最大化平均值,二分
题目:http://poj.org/problem?id=3111 题意:给你n,k,n个数的v.w值,选出k个数,使得v之和/w之和最大化. 思路:一看到题目,这不是赤果果的贪心吗?为什么放在二分专 ...
- CodeForces-508A~D篇 div.2
链接:https://codeforc.es/contest/1038 A题: #include<bits/stdc++.h> using namespace std; typedef l ...
- CodeForces1006A - Adjacent Replacements
A. Adjacent Replacements time limit per test 1 second memory limit per test 256 megabytes input stan ...