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

SpringMVC源码深度解析之SpringServletContainerInitializer原理分析_第1张图片

SpringMVC

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

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

Servlet与SpringMVC之间的关系

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

快速搭建Servlet环境


  
  
    javax.servlet
    javax.servlet-api
    3.1.0
  
  
    javax.servlet.jsp
    javax.servlet.jsp-api
    2.3.1
  

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 {

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

基于注解方式构建SpringMVC框架


  
    org.springframework
    spring-webmvc
    5.0.5.RELEASE
  
  
  
    javax.servlet
    javax.servlet-api
    3.1.0
  
  
    javax.servlet.jsp
    javax.servlet.jsp-api
    2.3.1
  

SpringMVC源码深度解析之SpringServletContainerInitializer原理分析_第2张图片

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

SpringMVC源码深度解析之SpringServletContainerInitializer原理分析_第3张图片

e0e6dc6222e91a0345f33f3b68b06950b17.jpg

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

@RestController
public class IndexController {

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

SpringMVC源码深度解析之SpringServletContainerInitializer原理分析_第4张图片

SpringMVC源码深度解析之SpringServletContainerInitializer原理分析_第5张图片

本文参考:

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

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

 

转载于:https://my.oschina.net/u/3995125/blog/3081947

你可能感兴趣的:(java,web.xml,测试)