互联网架构-SpringMVC源码深度解析-027:Servlet与SpringMVC关系

1 SpringMVC深度源码分析课程介绍

课题内容:
1.Servlet与SpringMVC之间的关系
2.Servlet框架线程是否安全
3.SpringMVC是如何完全无web.xml启动的?

2 基于ide构建ServletMaven工程

Servlet与SpringMVC关系
SpringMVC是基于Servlet封装的MVC框架。

Servlet简单的介绍
Servlet是sun公司提供的一门用于开发动态web资源的技术。
  Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
  1、编写一个Java类,实现servlet接口。
  2、把开发好的Java类部署到web服务器中。
按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet。

快速搭建Servlet环境
1.建立maven项目选择webapp
在这里插入图片描述
创建项目时候添加archetypeCatalog=internal参数,解决创建maven web项目慢的问题
在这里插入图片描述
2.引入Servlet的jar包
两种方式:tomcat自带Servlet;使用maven引用
在这里插入图片描述
3.项目引入tomcat jar包
在这里插入图片描述
4.创建java目录,Mark Directory as Sources Root
5.创建Servlet类并配置xml

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("this is a servlet");
    }
}
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.mayikt.servlet.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

基于注解方式配置

@WebServlet("/")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("this is a servlet");
    }
}

启动tomcat,测试结果:
在这里插入图片描述

3 如何证明Servlet线程是否安全

Servlet线程是否安全?
不安全,Servlet是单例的 在高并发情况下,可能会存在线程安全问题。

@WebServlet("/")
public class MyServlet extends HttpServlet {

    private Integer count = 0;

    public MyServlet() {
        System.out.println("MyServlet 无参构造函数被执行...");
    }

    // 如何证明servlet线程不安全 单例才会共享
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        count++;
        resp.getWriter().println("this is a servlet,count:" + count);
    }
    // 发送两次请求
    // 第一次请求 1  第二次请求 2
    // 如果发送多次请求,count累计在增加,说明count是共享的
}

验证结果:
在这里插入图片描述

4 ServletContainerInitializer用法

ServletContainerInitializer
在web容器启动时加载第三方依赖jar包,提供给第三方组件做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能。
每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类(全路径类名)。

ServletContainerInitializer实现类

@HandlesTypes(value = MyHandlesType.class)
public class MyServletContainerInitializer implements ServletContainerInitializer {

    /**
     * onStartup 作用是servlet容器初始化加载一些操作 比如第三方依赖信息、手动加载servlet、监听器、过滤器
     *
     * @param set            获取继承该MyHandlesType类所有子类class信息(不包含本身类)  感兴趣的类
     * @param servletContext
     * @throws ServletException
     */
    @Override
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        // 1.获取感兴趣的类
        for (Class<?> c : set) {
            System.out.println("c:" + c);
        }
        // 2.手动给容器添加servlet、监听器、过滤器
        ServletRegistration.Dynamic payServlet = servletContext.addServlet("payServlet", new PayServlet());
        payServlet.addMapping("/pay"); //设置映射地址
        // 如何能够让tomcat启动加载到该类MyServletContainerInitializer
        // tomcat 默认读取META-INF
    }
}

HandlesType指定的类及其子类

public class MyHandlesType {
}
public class MemberUtils extends MyHandlesType {
}
public class PayUtils extends MyHandlesType{
}

手动添加的servlet

public class PayServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("this is pay");
    }
}

测试结果:
在这里插入图片描述

5 基于注解方式构建SpringMVC框架

Springboot中实现没有web.xml基于注解方式启动

引入依赖

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.0.5.RELEASE</version>
</dependency>

在这里插入图片描述
SpringServletContainerInitializer作用:加载第三方依赖信息实现初始化操作

6 使用注解形式启动SpringMVC项目

@RestController
public class IndexController {

    @RequestMapping(value = "/", produces = "text/html;charset=UTF-8")
    public String index() {
        return "蚂蚁课堂 666";
    }
}
@Configuration
@ComponentScan("com.mayikt.controller")
@EnableWebMvc
public class SpringMvcConfig {
    // @EnableWebMvc 等同于开启springmvc注解方式
    // @Configuration 替代xml
    // @ComponentScan 替代扫包范围
    // DispatcherServlet
}
public class WebInitializer implements WebApplicationInitializer {
    // 使用WebApplicationInitializer替代web.xml
    // 为什么WebInitializer不需要注解,能够自动找到该类?
    @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注入到servlet容器中
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(app));
        // 4.设置url路径映射
        dispatcher.addMapping("/");
        dispatcher.setLoadOnStartup(1);// 设置优先级 最高表示最早被加载
    }
}

注意删除webapp目录下的所有内容
测试结果:
在这里插入图片描述

7 SpringServletContainerInitializer源码分析

Springmvc注解方式启动原理分析:

  1. 引入Spring-Web依赖Jar包,加载SpringServletContainerInitializer 提供给SpringMVC实现初始化;
  2. 使用注解@HandlesTypes WebApplicationInitializer;
  3. WebInitializer继承WebApplicationInitializer;
  4. Servlet容器在启动的时候加载WebInitializer;
  5. 调用onStartup方法回调传递servletContext;
  6. servletContext手动注册DispatcherServlet、配置文件。

原理:Sevlet容器在初始化的时候会加载到SpringServletContainerInitializer类,然后找@HandlesTypes定义类的子类,回调传递servletContext。然后手动注册DispatcherServlet、注册springmvc配置文件。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值