一、简介

  上篇文章讲了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实现的更多相关文章

  1. springboot源码之(内嵌tomcat)

    server---service----engine----host-----context---wrapper---servletStandardServer---StandardService-- ...

  2. SpringBoot源码篇:深度分析SpringBoot如何省去web.xml

    一.前言 从本博文开始,正式开启Spring及SpringBoot源码分析之旅.这可能是一个漫长的过程,因为本人之前阅读源码都是很片面的,对Spring源码没有一个系统的认识.从本文开始我会持续更新, ...

  3. springboot学习笔记:6.内置tomcat启动和外部tomcat部署总结

    springboot的web项目的启动主要分为: 一.使用内置tomcat启动 启动方式: 1.IDEA中main函数启动 2.mvn springboot-run 命令 3.java -jar XX ...

  4. Vue源码后记-其余内置指令(1)

    把其余的内置指令也搞完吧,来一个全家桶. 案例如下: <body> <div id='app'> <div v-if="vIfIter" v-bind ...

  5. Vue源码后记-其余内置指令(2)

    -- 指令这个讲起来还有点复杂,先把html弄上来: <body> <div id='app'> <div v-if="vIfIter" v-bind ...

  6. Vue源码后记-其余内置指令(3)

    其实吧,写这些后记我才真正了解到vue源码的精髓,之前的跑源码跟闹着玩一样. go! 之前将AST转换成了render函数,跳出来后,由于仍是字符串,所以调用了makeFunction将其转换成了真正 ...

  7. 10.源码分析---SOFARPC内置链路追踪SOFATRACER是怎么做的?

    SOFARPC源码解析系列: 1. 源码分析---SOFARPC可扩展的机制SPI 2. 源码分析---SOFARPC客户端服务引用 3. 源码分析---SOFARPC客户端服务调用 4. 源码分析- ...

  8. android studio应用修改到android源码中作为内置应用

    1. 方法一:导入,编译(太麻烦,各种不兼容问题) android studio和eclipse的应用结构目录是不同的,但是在android源码中的应用基本上都是使用的eclipse目录结构(在/pa ...

  9. 不是springboot项目怎么使用内置tomcat

    不是springboot项目怎么使用内置tomcat   解决方法: 1.pom.xml中添加以下依赖 <properties>  <tomcat.version>8.5.23 ...

随机推荐

  1. 相对和绝对路径、cd命令、创建和删除目录、rm命令 使用介绍

    第2周第1次课(3月26日) 课程内容:2.6 相对和绝对路径2.7 cd命令2.8 创建和删除目录mkdir/rmdir2.9 rm命令 2.6相对和绝对路径 任何一个文件都有一个从根开始的路径,绝 ...

  2. 从UI设计转向前端的艰辛过程,从背单词开始。。。

    很纠结到底是继续做UI设计还是转行前端呢?从刚开始的害怕代码到接触代码又喜欢代码的过程,我在想我是不是太飘了,我感觉我做事就是三分钟热度.我感觉学前端对我最大的阻碍就是英语单词了,10个单词里面最起码 ...

  3. tp5判断多模块下访问PC端和手机端

    现在很多网站的手机端和PC端都是分开的模块,这是问题就来了,有些手机端的用户输入了PC端的网址,直接访问了PC端.下面我教大家如何实现手机端用户访问PC时,跳转回手机端. 解决方法:把下面的代码放到公 ...

  4. 常用的iOS第三方资源

    一:第三方插件 1:基于响应式编程思想的oc 地址:https://github.com/ReactiveCocoa/ReactiveCocoa pod 'ReactiveCocoa', '~> ...

  5. js练习-两个栈实现队列

    目录 题 解 题 现在有个Q队列和栈A,栈B,栈只有两个方法,push()和pop(), 队列也只有两个方法,push()和pull(),队列的进和出都只能通过A和B的push和pop实现. // 大 ...

  6. usb2.0高速视频采集之68013A寄存器配置说明

    任何的固件编程离不开与与原理图参考,图纸中所采用的是USB的Slave_fifo传输方式,具体配置与图纸对应即可. •USB_IFCLK:同步Slave_FIFO模式,输入频率范围5M-48M,在FP ...

  7. 深入理解 Java 方法

    方法(有的人喜欢叫函数)是一段可重用的代码段.

  8. RequireJS 打包工具

    r.js是RequireJS的一个附产品,支持在 NodeJS环境下运行AMD程序,并且其包含了一个名为RequireJS Optimizer的工具,可以为项目完成合并脚本等优化操作 RequireJ ...

  9. 【JS】325- 深度理解ES6中的解构赋值

    点击上方"前端自习课"关注,学习起来~ 对象和数组时 Javascript 中最常用的两种数据结构,由于 JSON 数据格式的普及,二者已经成为 Javascript 语言中特别重 ...

  10. 重新精读《Java 编程思想》系列之组合与继承

    Java 复用代码的两种方式组合与继承. 组合 组合只需将对象引用置于新类中即可. 比如我们有一个B类,它具有一个say方法,我们在A类中使用B类的方法,就是组合. public class B { ...