zoukankan      html  css  js  c++  java
  • 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的源码阅读之旅。

    小小的码农,大大的梦想
  • 相关阅读:
    SQLServer DMV Query
    SQL Server Logical/Physical Reads
    The include feature of SQL Server Index
    数据库教程:数据库常用对象
    数据库教程:数据库组成
    数据库教程(一):基本概念
    C#编程:依赖倒置原则DIP
    C#编程:AOP编程思想
    ASP.NET Core Web服务器
    DataTable实现分组
  • 原文地址:https://www.cnblogs.com/hello-shf/p/10952362.html
Copyright © 2011-2022 走看看