深入理解Servlet(下)

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

在这一篇文章里,将会讨论ServletContext以及Servlet映射规则。这两个知识点非常重要,ServletContext直接关系到SpringIOC容器的初始化,而Servlet映射规则与SpringMVC关系密切。

可以说,作为初学者只要把这两点搞清楚,那么对Spring/SpringMVC的理解将会超过70%的程序员。我没开玩笑,你随便抓一个身边的同事问问,Tomcat和Spring什么关系?SpringMVC和Servlet什么关系?估计没几个能给你讲清楚的。

我会先把SpringMVC讲得很简单,等大家觉得它就是个Servlet的时候,我又会把SpringMVC慢慢展开,露出它的全貌。此时你又会发现:SpringMVC is not only a Servlet.

主要内容:

  • ServletContext是什么
  • 如何获取ServletContext
  • Filter拦截方式之:REQUEST/FORWARD/INCLUDE/ERROR
  • Servlet映射器
  • 自定义DispatcherServlet
  • DispatcherServlet与SpringMVC
  • conf/web.xml与应用的web.xml

ServletContext是什么

ServletContext,直译的话叫做“Servlet上下文”,听着挺别扭,但其实就是个大容器,是一个map。服务器会为每个应用创建一个ServletContext对象:

  • ServletContext对象的创建是在服务器启动时完成的
  • ServletContext对象的销毁是在服务器关闭时完成的

ServletContext对象的作用是在整个Web应用的动态资源(Servlet/JSP)之间共享数据。例如在AServlet中向ServletContext对象保存一个值,然后在BServlet中就可以获取这个值。

这种用来装载共享数据的对象,在JavaWeb中共有4个,而且更习惯被成为“域对象”:

  • ServletContext域(Servlet间共享数据)
  • Session域(一次会话间共享数据,也可以理解为多次请求间共享数据)
  • Request域(同一次请求共享数据)
  • Page域(JSP页面内共享数据)

它们都可以看做是map,都有getAttribute()/setAttribute()方法。来看一下物理磁盘中的配置文件与内存对象之间的映射关系:

每一个动态web工程,都应该在WEB-INF下创建一个web.xml,它代表当前整个应用。Tomcat会根据这个配置文件创建ServletContext对象

如何获取ServletContext

还记得GenericServlet吗?它在init方法中,将Tomcat传入的ServletConfig对象的作用域由局部变量(方法内使用)提升到成员变量。并且新建了一个getServletContext():

getServletContext()内部其实就是config.getServletContext()

也就是说ServletConfig对象可以得到ServletContext对象。但是这并不意味这ServletConfig对象包含着ServletContext对象,而是ServletConfig维系着ServletContext的引用。

其实这也很好理解:servletConfig是servletContext的一部分,就像他儿子。你问它父亲是谁,它当然能告诉你。

另外,Session域和Request域也可以得到ServletContext:

session.getServletContext();
request.getServletContext();

本质就是,用域对象获得域对象

最后,还有个冷门的,我在监听器那一篇讲过了:

事件对象就是对事件源(被监听对象)的简单包装

所以,获取ServletContext的方法共5种(page域这里不考虑,JSP太少用了):

  • ServletConfig#getServletContext()
  • GenericServlet#getServletContext()
  • HttpSession#getServletContext()
  • HttpServletRequest#getServletContext()
  • ServletContextEvent#getServletContext()

Filter拦截方式之:REQUEST/FORWARD/INCLUDE/ERROR

在很多人眼里,Filter只能拦截Request:

这样的理解还是太片面了。

其实配置Filter时可以设置4种拦截方式:

很多人要么不知道,要么理解得不够清晰。

这里,我先帮大家把这4种方式和重定向(Redirect)剥离开,免得有人搞混,它们是完全两类(前者和Request有关,后者通过Response发起),以FORWARD为例:

蓝色:重定向,橙色:转发

我们日常开发中,FORWARD用的最多的场景就是转发给JSP,然后模板输出HTML。

Redirect和REQUEST/FORWARD/INCLUDE/ERROR最大区别在于:

重定向会导致浏览器发送2次请求,FORWARD们是服务器内部的1次请求

了解这个区别之后,我提一个很奇怪的问题:为什么这4种只引发1次请求?

是不是听傻了?我接下来给的答案,属于意料之外情理之中的那种:

因为FORWARD/INCLUDE等请求的分发是服务器内部的流程,不涉及浏览器

还记得如何转发吗:

我们发现通过Request或者ServletContext都可以得到分发器Dispatcher,但由于ServletContext代表整个应用,我更倾向于认为:ServletContext拥有分发器,Request是找它借的。

分发器是干嘛的?分发请求:REQUEST/FORWARD/INCLUDE/ERROR。REQUEST是浏览器发起的,而ERROR是发生页面错误时发生的,稍微特殊些。

所以,所谓Filter更详细的拦截其实是这样:

灰色块:Filter

最外层那个圈,可以理解成ServletContext,FORWARD/INCLUDE这些都是内部请求。如果在web.xml中配置Filter时4种拦截方式全配上,那么服务器内部的分发跳转都会被过滤。

当然,这些都是可配置的,默认只拦截REQUEST,也就是浏览器来的那一次。

Servlet映射器

上一篇说了很多Servlet的源码,也介绍了Servlet的作用就是处理请求。但是对于每个请求具体由哪个Servlet处理,却只字未提。其实,每一个URL要交给哪个Servlet处理,具体的映射规则都由一个映射器决定:

这所谓的映射器,其实就是Tomcat中一个叫Mapper的类。

它里面有个internalMapWrapper方法:

定义了7种映射规则:

  • 1.精确匹配 2.前缀匹配

  • 3.扩展名匹配

  • 4.5.6 欢迎列表资源匹配?

  • 7.如果上面都不匹配,则交给DefaultServlet,就是简单地用IO流读取静态资源并响应给浏览器。如果资源找不到,报404错误

简单来说就是:

对于静态资源,Tomcat最后会交由一个叫做DefaultServlet的类来处理对于Servlet ,Tomcat最后会交由一个叫做 InvokerServlet的类来处理对于JSP,Tomcat最后会交由一个叫做JspServlet的类来处理

自定义DispatcherServlet

web.xml

DispatcherServlet

知道了映射器的映射规则后,我们来分析下上图中三种拦截方式会发生什么。

但在此之前,我必须再次强调,我从没说我现在写的是SpringMVC的DispatcherServlet,这是我自己自定义的一个普通Servlet,恰好名字叫DispatcherServlet而已。所以,下面的内容,请当做一个普通Servlet的映射分析。

  • *.do:拦截.do结尾

此时,各个Servlet和谐相处,没问题。

  • /*:拦截所有

拦截localhost:8080

拦截localhost:8080/index.html

拦截localhost:8080/index.jsp

也就是说,/*这种配置,相当于把DefaultServlet、JspServlet以及我们自己写的其他Servlet都“短路”了,它们都失效了。

这会导致两个问题

  • JSP无法被编译成Servlet输出HTML片段(JspServlet短路)
  • HTML/CSS/JS/PNG等资源无法获取(DefaultServlet短路)

  • /:拦截所有,但不包括JSP

拦截localhost:8080

拦截localhost:8080/index.html

不拦截JSP

虽然JSP不拦截了,但是DefaultServlet还是“短路”了。而DispatcherServlet把本属于DefaultServlet的工作也抢过来,却又不会处理(IO读取静态资源返回)。

怎么办?

DispatcherServlet与SpringMVC

SpringMVC的核心控制器叫DispatcherServlet,映射原理和我们上面山寨版的一样,因为本质还是个Servlet。但SpringMVC提供了一个标签,解决上面/无法读取静态资源的问题:

<!-- 静态资源处理  css js imgs -->
<mvc:resources location="/resources/**" mapping="/resources"/>

其他的我也不说了,一张图,大家体会一下DispatcherServlet与SpringMVC到底是什么关系:

DispatcherServlet确实是一个Servlet,但它只是入口,SpringMVC要比想象的庞大。

conf/web.xml与应用的web.xml

conf/web.xml指的是Tomcat全局配置web.xml。

它里面配置了两个Servlet:

也就是JspServlet和DefaultServlet的映射路径。

我们可以按Java中“继承”的思维理解conf/web.xml:

conf/web.xml中的配置相当于写在了每一个应用的web.xml中。

相当于每个应用默认都配置了JSPServlet和DefaultServlet处理JSP和静态资源。

如果我们在应用的web.xml中为DispatcherServlet配置/,会和DefaultServlet产生路径冲突,从而覆盖DefaultServlet。此时,所有对静态资源的请求,映射器都会分发给我们自己写的DispatcherServlet处理。遗憾的是,它只写了业务代码,并不能IO读取并返回静态资源。JspServlet的映射路径没有被覆盖,所以动态资源照常响应。

如果我们在应用的web.xml中为DispatcherServlet配置/*,虽然JspServlet和DefaultServlet拦截路径还是.jsp和/,没有被覆盖,但无奈的是在到达它们之前,请求已经被DispatcherServlet抢去,所以最终不仅无法处理JSP,也无法处理静态资源。

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

进群,大家一起学习,一起进步,一起对抗互联网寒冬

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/212237.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTML简介

1&#xff0c;网页 网页的相关概念 1.1&#xff0c;什么是网页&#xff1f; 网页是构成网站的基本元素&#xff0c;它通常由图片&#xff0c;链接&#xff0c;文字&#xff0c;声音&#xff0c;视频等元素组成。其实就是一个常见以.htm或.html后缀结尾的文件&#xff0c;因此…

鸿蒙是Android套壳么,当然不是,ArkTS还是很有意思的

前段时间看新闻&#xff0c;说是明年开始鸿蒙就要和andorid脱钩了。 大概就是这样的&#xff1a; 看到这个&#xff0c;我兴趣就来了。我有个华为P30&#xff0c;升级过鸿蒙系统&#xff0c;用起来也没啥变化&#xff0c;兼容andorid应用&#xff0c;然后就是开机去掉了Powere…

Mover Creator--功能简介

Mover Creator是一款AFSIM软件工具&#xff0c;提供方便易用的基于GUI的应用程序&#xff0c;帮助用户创建用于空中运动器的AFSIM输入文件&#xff0c;包括WSF_P6DOF_MOVER和WSF_GUIDED_MOVER。使用自定义定义的基于图形的模型定义&#xff0c;用户可以对飞机、武器和发动机进行…

配置typroa上传图片到gitee

在typora这个位置下载插件 在picgo.exe文件夹下输入cmd 打开命令行输入如下命令安装相关插件 .\picgo install gitee-uploader .\picgo install super-prefix 之后按照官方文档更改相关配置 官方文档参考 https://picgo.github.io/PicGo-Core-Doc 博客参考&#xff1a;…

【每日OJ —— 226. 翻转二叉树】

每日OJ —— 226. 翻转二叉树 1.题目&#xff1a;226. 翻转二叉树2.解法2.1.算法讲解2.2.代码实现2.3.代码提交通过展示 1.题目&#xff1a;226. 翻转二叉树 2.解法 2.1.算法讲解 我们从根节点开始&#xff0c;递归地对树进行遍历&#xff0c;并从叶子节点先开始翻转。如果当前…

分治—快速选择算法

文章目录 &#x1f347;215.数组中的第K个最大元素&#x1f348;1. 题目&#x1f349;2. 算法原理&#x1f34a;3. 代码实现 &#x1f34b;LCR 159. 库存管理 III&#x1f34c;1. 题目&#x1f34d;2. 算法原理&#x1f96d;代码实现 &#x1f347;215.数组中的第K个最大元素 …

《数据结构与测绘程序设计》试题详细解析(仅供参考)

一. 选择题&#xff08;每空2分&#xff0c;本题共30分&#xff09; &#xff08;1&#xff09;在一个单链表中&#xff0c;已知q所指结点是p所指结点的前驱结点&#xff0c;若在q和p之间插入结点s&#xff0c;则执行( B )。 A. s->nextp->next; p->nexts; B. q…

九章正式推出『智能驾驶产业数据库』

为了更好地研究产业变化趋势&#xff0c;在定性分析之外增加更多定量分析的内容&#xff0c;从而帮助自动驾驶产业内的朋友们更快速、更精准地把握市场变化&#xff0c;2022年底&#xff0c;九章决定要做智能驾驶产业数据库。 历时将近一年后&#xff0c;从敲定数据库负责人&am…

阅读笔记|A Survey of Large Language Models

阅读笔记 模型选择&#xff1a;是否一定要选择参数量巨大的模型&#xff1f;如果需要更好的泛化能力&#xff0c;用于处理非单一的任务&#xff0c;例如对话&#xff0c;则可用选更大的模型&#xff1b;而对于单一明确的任务&#xff0c;则不一定越大越好&#xff0c;参数小一…

L1-015:跟奥巴马一起画方块

题目描述 美国总统奥巴马不仅呼吁所有人都学习编程&#xff0c;甚至以身作则编写代码&#xff0c;成为美国历史上首位编写计算机代码的总统。2014年底&#xff0c;为庆祝“计算机科学教育周”正式启动&#xff0c;奥巴马编写了很简单的计算机代码&#xff1a;在屏幕上画一个正方…

[GPT-1]论文实现:Improving Language Understanding by Generative Pre-Training

Efficient Graph-Based Image Segmentation 一、完整代码二、论文解读2.1 GPT架构2.2 GPT的训练方式Unsupervised pre_trainingSupervised fine_training 三、过程实现3.1 导包3.2 数据处理3.3 模型构建3.4 模型配置 四、整体总结 论文&#xff1a;Improving Language Understa…

前端笔记(一):HTML5 入门学习

前言&#xff1a; 在完成 Java 的 SpringBoot 学习并练习了几个项目后&#xff0c;出于对编程的兴趣和没有组织的局限性&#xff0c;为了开发一些个人的小项目&#xff0c;我将开始前端部分的学习&#xff0c;预计会学到 Vue 框架&#xff0c;同时会把自己的学习笔记发布成博客…

WPF实现文字纵向排布的TabItem

文章目录 基本用法文字竖排显示 WPF布局 基本用法 WPF中的TabControl是一个容器控件&#xff0c;用于在单个窗体或页面中承载多个选项卡。每个选项卡可以包含不同的控件&#xff0c;用于显示不同的内容&#xff0c;其最简单的调用方法如下&#xff0c;只需在TabControl中无脑…

Qt Creator 11.0.3同时使用Qt6.5和Qt5.14.2

Qt Creator 11.0.3同时使用Qt6.5和Qt5.14.2 概要方法1.打开Qt Creator中的Kit&#xff0c;这里我直接附上几张截图&#xff0c;不同的版本打开位置可能有所不同&#xff0c;总之最终目的是要打开构建套件&#xff08;Kit&#xff09;2.可以看到构建套件里面有包含了“构建套件K…

Java基础-----Date类及其相关类(一)

文章目录 1. Date类1.1 简介1.2 构造方法1.3 主要方法 2. DateFormat 类2.1 简介2.2 实例化方式一&#xff1a;通过静态方法的调用2.2 实例化方式二&#xff1a;通过创建子类对象 3. Calendar类4. GregorianCalendar 1. Date类 1.1 简介 java.util.Date:表示指定的时间信息&a…

Structured Streaming: Apache Spark的流处理引擎

欢迎来到我们的技术博客&#xff01;今天&#xff0c;我们要探讨的主题是Apache Spark的一个核心组件——Structured Streaming。作为一个可扩展且容错的流处理引擎&#xff0c;Structured Streaming使得处理实时数据流变得更加高效和简便。 什么是Structured Streaming&#…

高端大气简历模板(精选8篇)

想要让简历在众多求职者中脱颖而出&#xff0c;吸引HR的眼球吗&#xff0c;可以看看这8篇精选的高端大气简历模板&#xff01;本文为大家提供了多种行业、职位的简历案例&#xff0c;助大家打造一份令人惊艳的简历&#xff0c;轻松斩获心仪职位&#xff01; 高端大气简历模板下…

【Vulnhub 靶场】【HackathonCTF: 2】【简单】【20210620】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/hackathonctf-2,714/ 靶场下载&#xff1a;https://download.vulnhub.com/hackathonctf/Hackathon2.zip 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年06月20日 文件大小&#xff1a;2.6 GB 靶场作者&…

Opencv拖动条控制均值滤波卷积核大小,拖动条控制是否保存(涉及知识点:cv2.createTrackbar和cv2.getTrackbarPos的使用)

带拖动条的均值滤波import timeimport cv2 import numpy as npdef callback(int):passcv2.namedWindow(dst,cv2.WINDOW_AUTOSIZE)# 创建trackbar (trackbarname,winname,value,count,callback,userdata) cv2.createTrackbar(ksize, dst, 3, 30, callback) cv2.createTrackbar(s…

基于Amazon Bedrock的企业级生成式AI平台

基于Amazon Bedrock的企业级生成式AI平台 2023.12.2版权声明&#xff1a;本文为博主chszs的原创文章&#xff0c;未经博主允许不得转载。 Amazon Bedrock 是一项新的 AWS 服务&#xff0c;可让企业通过 API 轻松利用和自定义生成式 AI 模型。公司现在可以构建和扩展人工智能应…