首页 > 其他分享 >【Spring MVC + Tomcat】Spring MVC 传统VS现代方式的启动过程对比

【Spring MVC + Tomcat】Spring MVC 传统VS现代方式的启动过程对比

时间:2023-04-17 18:11:09浏览次数:32  
标签:容器 Tomcat 启动 SpringMVC Spring MVC Servlet

1  前言

这节我们来讨论下 Spring MVC 传统和现在的启动方式的不同,可能大家现在上手就是SpringBoot直接给我们内置Tomcat,我们最多也就是改改配置就完事了,我记得我上学的时候写SSM的时候,还要整理各种Jar包和配置,这节我们就来对比下两种启动方式是如何启动Spring MVC的哈。

2  传统和现代

我们先来看下哪些方式的是传统,哪些是现代启动:

  • 传统方式:打成war包并放入Tomcat等Servlet容器下面运行的,都认为是SpringMVC传统的启动方式。基于web.xml(配置文件)的方式启动肯定算传统的,但由于现在web.xml几乎已经绝迹,肯定是传统的,这里就不解释他了。与之相对的就是基于编程(写代码)的方式启动,流行于前几年的SSM(Spring、SpringMVC、MyBatis)中,当然也算传统的。
  • 现代方式:和SpringBoot连用且采用内嵌Web服务器并打成jar包直接运行的,可以认为是SpringMVC现代的启动方式。

3  传统的启动过程

在上一节中讲到,通过一个“桥梁”的接口ServletContainerInitializer(Servlet容器初始化器)把Tomcat的启动和初始化进程带到了SpringMVC里。
在这个“桥式”接口上可以指定“感兴趣”的类或接口,SpringMVC指定的是WebApplicationInitializer(Web应用初始化器)接口,意图已经很明显,就是通过这个初始化器接口来完成SpringMVC应用的启动和初始化。
我们先来看下这个初始化接口,如下图:

它只有一个onStartup方法,方法只有一个参数就是ServletContext,这个ServletContext由Tomcat创建好后提供给SpringMVC,SpringMVC在启动过程中调用这个onStartup方法,在这个方法内完成自身的创建和初始化,还要把Servlet和Filter等注册到ServletContext里。
这些工作都是SpringMVC要做的,而不是我们要做的,所以SpringMVC肯定已经实现了这个接口,我们查看下类型信息,

我们发现了一个看着很重要的类,就是:AbstractAnnotationConfigDispatcherServletInitializer,可惜这个类是抽象的,肯定是不能直接用的,但是它里面已经包含了刚刚上面提到的所有完整的启动逻辑过程。
如果你对SSM很熟悉或Spring的官方文档看的很熟悉的话,你一定知道这个类是怎么用的。是的,我们需要定义一个类来继承它即可。继承之后,我们需要提供三方面信息,一个是用于注册到根容器中的类,一个是用于注册到Servlet容器中的类,一个是核心Servlet的映射URL。
注意,这里说的容器指的是Spring的ApplicationContext这个容器,其中根容器和Servlet容器是父子关系,且在SpringMVC中核心Servlet映射的URL必须是"/"。

另外引申一下:

servlet3.0不再使用web.xml配置文件启动容器,取而代之的一个实现了AbstractAnnotationConfigDispatcherServletInitializer的类,实现3个方法:getRootConfigClasses、getServletConfigClasses、getServletMappings。
3个方法的作用:
(1)getRootConfigClasse:获取根容器的配置类(Spring配置文件)父容器。
(2)getServletConfigClasses:获取web容器的配置类(Spring mvc配置文件)创建子容器。
(3)getServletMappings:获取DispatcherServlet的映射信息。

贴个代码示例:

//SpringMVC只扫描controller组件
@ComponentScan(value = "org.kuku",
        includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class),
useDefaultFilters = false) //禁用默认的过虑规则
@EnableWebMvc
public class MvcConfig {

}
// Spring的容器不扫描controller组件
// 标识配置类
@ComponentScan(value = "org.kuku", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)) // 配置包扫描Control以外的组件
@PropertySource("classpath:db.properties") // 读取db.properties配置文件
@MapperScan("org.kuku.mapper") // 配置mapper接口包扫描
@EnableAspectJAutoProxy // 开启AOP注解模式
@EnableTransactionManagement // 开启spring事务管理
public class SpringConfig {
}
// web容器启动的时候就会创建对象 调用方法 初始化容器 以及前端控制器
public class MyWebappInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // 获取根容器的配置类(Spring配置文件)父容器
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    // 获取web容器的配置类(Spring mvc配置文件)创建子容器
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{MvcConfig.class};
    }

    // 获取DispatcherServlet的映射信息
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

这就是以编程的方式来完成SpringMVC的启动。我们自己定义的这个类就是前文提到的"感兴趣"的类。
这个类是不用(或不能)向Spring容器注册的,因为这个类是感兴趣的类,所以Tomcat会从jar包里把它找出来,这样SpringMVC就拿到了我们定义的这个类。
其实最主要的是这时候根本还没有Spring容器呢,因为Spring容器就是在这个类里才创建出来的。
整个启动过程要做的事情:
(1)创建根容器。

(2)然后把根容器放入ServletContext中,因为ServletContext在应用运行期间一直存在,所以根容器是一个全局性的,也一直存在。

(3)接着创建Servlet容器,容器类也是基于注解的,和根容器类是一样的。

(4)然后使用Servlet容器去创建核心Servlet。

(5)接着把核心Servlet注册到ServletContext中。

(6)接着再注册一些过滤器。

4  现代的启动过程

当SpringMVC遇上SpringBoot后,确实方便了开发人员,那是因为SpringBoot把所有的代码都写好了,并通过自动配置来应用这些代码。因为是基于SpringBoot的,所以就要按照SpringBoot的Style了,一切都要从入口类SpringApplication说起。
首先创建容器:

这个容器类的名称是:AnnotationConfigServletWebServerApplicationContext,它是SpringBoot为自己专门“量身打造”的,与之前相比这个容器类最大的不同就是,它要去创建和启动Tomcat。
容器刷新时创建并启动Tomcat:

在启动的过程中,要把ServletContext对象从Tomcat里带出来,因为它是由Tomcat创建出来的。在创建Tomcat时,实际是把Spring容器实例自己本身传进去了,然后通过一个方法参数带了出来。如下方法:

然后再把Spring容器放入ServletContext中,同时ServletContext被保存到Spring容器实例的一个字段中,方便后续使用如下图:

然后把核心Servlet注册为Bean,如下图:

接着把核心Servlet注册到ServletContext中,就等于注册到了Tomcat中,如下图:

5  现代方式 VS 传统方式

相同点:
都需要创建Spring容器
都需要把该容器放入ServletContext中
都需要把核心Servlet注册到ServletContext中。

不同点:
传统方式可以创建两个Spring容器,现代方式只有一个容器。
传统方式是Tomcat先启动,然后带动Spring容器的创建,现代方式是容器先创建,在刷新时再带动Tomcat的启动。

重要点:
虽然启动Tomcat的时机和方式不同,但是把ServletContext从Tomcat里取出来的方式是一样的,都要用到上一篇提到的“桥梁”接口。
它是用来触发一些初始化工作,主要就是注册核心Servlet到ServletContext里:

给开发人员剩下些什么呢?在一般不复杂的情况下,就是剩一个application.yml配置文件了。开发人员在里面配置就可以了,这些配置项肯定都是提前预设好的,在启动时会去读取这些配置值,并应用在初始化中,

框架越来越完善和智能,留给普通开发人员的工作几乎只剩CRUD了,努力吧,不然就真的只会这些了,好心酸。

6  小结

本文我们对比了下传统方式和现在启动方式的区别,有理解不对的地方欢迎指正哈。

标签:容器,Tomcat,启动,SpringMVC,Spring,MVC,Servlet
From: https://www.cnblogs.com/kukuxjx/p/17326448.html

相关文章

  • Spring 教程—REST 客户端详解
    Spring框架为调用REST端点提供了以下选择:WebClient -非阻塞、响应式客户端和fluentAPI。RestTemplate -带有模板方法API的同步客户端。HTTP接口 -注解式接口,并生成动态代理实现。一、 WebClientWebClient 是一个非阻塞的、响应式的客户端,用于执行HTTP请求。它在5.0中引......
  • idea中tomcat中文显示乱码问题解决
    组合拳:1、找到tomcat安装目录下面的logging.properties文件如下图:2、修改java.util.logging.ConsoleHandler.encoding=utf-8为java.util.logging.ConsoleHandler.encoding=UTF-8 3、打开idea,在file->settings->appearence里修改Name的值为支持中文的字体4、修改file......
  • 不同版本的Spring Framework有哪些主要功能?
    官方地址:https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions SpringFramework版本 JDKJavaEE/JakartaEESpringBoot支持新特性eof6.x6.0.xJDK 17-21JakartaEE9-10Springboot3.x What'sNewinSpring......
  • Java SpringBoot 7z 压缩、解压
    JavaSpringBoot7z压缩、解压cmd7z文件压缩7z压缩测试添加依赖<dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.12</version></dependency><dependency......
  • Springboot使用RestTemplate发送Post请求postForEntity (application/json)的坑
    当使用RestTemplate进行http请求时,的确很方便,但是当需要进行post请求时遇到了坑1POST传递参数:采用LinkedMultiValueMap,不能使用HashMapStringurl='http://posturl';MultiValueMap<String,String>map=newLinkedMultiValueMap<String,String>();map.add(......
  • 深谈Spring如何解决Bean的循环依赖
    1.什么是循环依赖Java循环依赖指的是两个或多个类之间的相互依赖,形成了一个循环的依赖关系,这会导致程序编译失败或运行时出现异常。下面小岳就带大家来详细分析下Java循环依赖。简单来讲就是:假设有两个人是:A和B,A想要向B借钱,但B需要先向A借钱。这种情况就形成了循环依赖关系,无......
  • springboot整合swagger2
     1.正文1.1什么是swagger2Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务的接口文档 .接口:controller相应的路径方法Swagger2是一款前后端分离开发中非常实用的API管理工具,它可以帮助开发者根据约定规范自动生成API文档,并支持......
  • Spring AOP官方文档学习笔记(二)之基于注解的Spring AOP
    1.@Aspect注解(1)@Aspect注解用于声明一个切面类,我们可在该类中来自定义切面,早在Spring之前,AspectJ框架中就已经存在了这么一个注解,而Spring为了提供统一的注解风格,因此采用了和AspectJ框架相同的注解方式,这便是@Aspect注解的由来,换句话说,在Spring想做AOP框架之前,AspectJAOP框......
  • spring事务传播
    采用编程式事务1、getCurrentSession()与openSession()的区别?*采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()创建的session则不会*采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession创建的session必须手......
  • spring工具类
    文件资源操作:org.springframework.core.io.Resource接口,是为了统一各种类型的资源而定义的1.访问文件资源org.springframework.core.io.ClassPathResource类路径进行访问org.springframework.core.io.FileSystemResource文件系统的绝对路径进行访问org.springframework.web.conte......