SpringMVC源码深度解析之SpringServletContainerInitializer原理分析

SpringMVC

对SpringMVC或者其它比较成熟的MVC框架而言,解决的问题无外乎以下几点:

  • 将web页面的请求传给服务器
  • 根据不同的请求处理不同的逻辑单元
  • 返回处理结果数据并跳转至响应的页面

Servlet与SpringMVC之间的关系

Spring的MVC是基于Servlet功能实现的,通过实现Servlet接口的DispatcherServlet来封装其核心功能实现。

快速搭建Servlet环境

<dependencies> <!-- 添加Servlet支持 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> </dependencies>

servlet线程是否安全?

不安全,构造函数只执行一次

ServletContainerInitializer接口

在web容器启动时会做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能。

每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类。

1、Servlet容器启动会扫描,当前应用里面每一个jar包的ServletContainerInitializer的实现
2、提供ServletContainerInitializer的实现类;必须绑定在META-INF/services/javax.servlet.ServletContainerInitializer,文件的内容就是ServletContainerInitializer实现类的全类名;

META-INF:tomcat默认就会去读取的

案例演示:

@HandlesTypes(value = MyHandlesType.class)//该注解声明的类,会被注入到set中,如果没有合适的类,set为null public class MyServletContainerInitializer implements ServletContainerInitializer {

1/\*\* 2 \* @param set **感兴趣类型 也就是MyHandlesType 所有子类型** 3 \* @param servletContext 4 \* @throws ServletException 5 \*/ 6public void **onStartup**(Set<Class<?>> set, ServletContext servletContext) throws ServletException { 7 **// 1.打印所有感兴趣的类型** 8 for (Class<?> c : set) { 9 System.out.println(c); 10 } 11 **// 2.servletContext 手动注册过滤器、servlet、监听器** 12 ServletRegistration.Dynamic payServlet = servletContext.addServlet("payServlet", new PayServlet()); 13 payServlet.addMapping("/pay"); 14}

}

基于注解方式构建SpringMVC框架

<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.5.RELEASE</version> </dependency> <!-- 添加Servlet支持 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> </dependencies>

springmvc是如何实现无web.xml配置,靠的就是****ServletContainerInitializer

SpringServletContainerInitializer的作用:加载一些第三方的依赖信息

@RestController public class IndexController {

1@RequestMapping(value = "/",produces="text/html;charset=UTF-8") 2public String index() { 3 return "success..."; 4} 5/\*\* 6 \* springmvc环境的时候需要配置那些东西? 7 \* SpringMVC启动的时候如何实现没有web.xml 8 \*/

}

@Configuration @ComponentScan("com.mayikt.controller") @EnableWebMvc public class SpringMvcConfig { //@EnableWebMvc 等于开启SpringMVC注解方式 //@Configuration xml // @ComponentScan("com.mayikt.controller") mvc 扫包范围 //DispatcherServlet }

public class WebInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { // 1.启动SpringMVC 容器 类注入到Spring中 AnnotationConfigWebApplicationContext app = new AnnotationConfigWebApplicationContext();// 启动SpringMVC Web // 2.注入我们的springmvc 的配置文件 app.register(SpringMvcConfig.class); // 3. 将我们的DispatcherServlet 注入到 serlvet容器中 ServletRegistration.Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(app)); // 4.填写url路径映射 dynamic.addMapping("/"); dynamic.setLoadOnStartup(1);// 优先级最高表示 最早被加载 } // 基本配置已经ok呢? web.xml ? 使用WebApplicationInitializer 替代web.xml //为什么这个类WebInitializer 不需要注解呢? 能够自动的找到该类呢? }

SpringServletContainerInitializer源码分析

SpringServletContainerInitializer:

Servlet3.0引入的接口,用在web应用启动时动态添加servlet、filter和listener

基于spi机制,****META-INF/services/javax.servlet.ServletContainerInitializer文件中存放实现该接口的类,这些类会被容器调用;

只能使用在jar文件中,不能在web项目中使用。

进入:org.springframework.web.SpringServletContainerInitializer

@HandlesTypes({WebApplicationInitializer.class}) public class SpringServletContainerInitializer implements ServletContainerInitializer { public SpringServletContainerInitializer() { } public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { ... }

SpringServletContainerInitializer 为spring中实现ServletContainerInitializer接口的唯一类,该类主要是从容器获取实现WebApplicationInitializer的类,并且按照次序****(javax.annotation.Priority)调用其onStartup方法

我们定义的WebInitializer实现了****WebApplicationInitializer接口

public class WebInitializer implements WebApplicationInitializer { public void onStartup(javax.servlet.ServletContext servletContext) throws ServletException { .... } }

原理:实现了****WebApplicationInitializer 接口的类会被Spring初始化;由于web项目中不能使用spi机制(未定位),所以如果需要动态添加servlet、filter和listener,就可以实现该接口,交由spring初始化。

springmvc是如何替代web.xml

使用:SpringServletContainerInitializer 提供给SpringMVC实现初始化

debug:可以看到****WebApplicationInitializer子类有我们自定义的WebInitializer

本文参考:

蚂蚁课堂:http://www.mayikt.com/

文档https://docs.oracle.com/javaee/7/api/javax/servlet/ServletContainerInitializer.html?is-external=true

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )