码迷,mamicode.com
首页 > 编程语言 > 详细

【聊透SpringMVC】抬高视角和追本溯源

时间:2020-12-14 13:58:28      阅读:18      评论:0      收藏:0      [点我收藏+]

标签:nta   网络   对象   and   类加载   应用信息   png   etc   目录   

2019年我在公众号写了《品Spring》和《玩转SpringBoot》这两个系列的文章。但平心而论大部分开发者还是使用SpringMVC最多。

所以我打算写一个SpringMVC系列,就叫《聊透SpringMVC》,因为我越来越觉得聊一件事如果没聊透,那就等于没聊。

抬高视角

要看透一件事情,必须要抬高自己的视角,因为有一句诗就是“不识庐山真面目,只缘身在此山中”。

请看一个高层次的请求处理过程,如下图01:
技术图片

第一步:用户和Tomcat间建立连接并通过网络发送请求报文给Tomcat。

第二步:Tomcat接收用户的报文然后解析报文,并用解析结果生成一个HttpServletRequest对象。

第三步:Tomcat同时生成一个空的HttpServletResponse对象,并使用这两个对象去调用SpringMVC。

第四步:SpringMVC从HttpServletRequest对象中获取参数,然后进行业务处理。

第五步:SpringMVC把业务处理的结果放入HttpServletResponse中,处理流程回到Tomcat中。

第六步:Tomcat把HttpServletResponse对象中的内容转化为报文并通过网络发回给用户。

第七步:用户接收到报文并使用浏览器展示出来。

用户和Tomcat分别位于不同的地方,所有使用Socket交互。Tomcat和SpringMVC位于一个进程内,所以可以直接调用。

把SpringMVC看作一个整体,和它密切相关的就是HttpServletRequest和HttpServletResponse两个对象,前者用于获取参数信息,后者用于存放处理结果。

抬高视角后,我们发现了SpringMVC的边界,SpringMVC只需要处理好界内事情即可,剩余的由Tomcat来负责。

追本溯源

Tomcat早就有了,SpringMVC后来才出现,它俩之间没有什么关系。那Tomcat为啥能够调用到SpringMVC呢?

那是因为它们都是Java Web规范下的产物。Java Web规范简单来说主要就是Servlet。Servlet这个词就是Server和Applet的结合体,意为运行在服务器上的小型程序。

Servlet本身是一个Java接口,不过我们通常把任何实现了这个接口的类也称作Servlet。Servlet有一个最大的特点就是它可以和指定的URL相关联。

当我们请求一个URL的时候,最终会来到和它关联的Servlet里面。所以Servlet是负责处理请求的地方,但是如何从URL来到Servlet里呢,这是Servlet管不了的。

负责这个事情的叫做Servlet容器。Servlet类就运行在Servlet容器中,容器负责接受请求,Servlet负责处理请求。这样的话所有环节就都通顺了。

因此Servlet容器就是Tomcat了,Servlet类就是SpringMVC了。所以说SpringMVC是基于Servlet构建起来的。这一切都是源于Servlet规范。

一座小桥

按照Servlet规定,SpringMVC应用应该被打成war包,然后放入Tomcat下面,当Tomcat成功启动后,一切自然OK。这是怎么做到的呢?

那是因为Servlet在它们之间定义了一座小桥,其实就是一个接口。这个接口由SpringMVC来实现,由Tomcat来调用这个实现。

请看这个接口,如下图02:
技术图片

接口只有一个方法,方法的第一个参数是“感兴趣”的类的集合,哪些类才算是感兴趣的呢?又如何指定呢?继续往下看。

请看SpringMVC对该接口的实现类,如下图03:
技术图片

在类的上面通过@HandlesTypes注解指定的类就是感兴趣的类。这里指定的是一个叫做WebApplicationInitializer(web应用初始化器)的接口,那它的所有实现类就是感兴趣的类。

那Tomcat如何知道有这么一个实现类存在呢?因为Servlet又给出了规范,哈哈,规范走天下啊。规范规定:

在war包里的META-INF/services目录下,必须有个名为javax.servlet.ServletContainerInitializer的文件,文件内容必须是一个实现了该接口的类的全名。且这个实现类上可以使用@HandlesTypes注解,来指定你感兴趣的类。

这样Tomcat只要从每个war包里读出这个实现类的全名,然后就可以使用反射实例化它,接着调用它的onStartup方法就行了。

这样Tomcat的启动流程通过这座小桥就来到了SpringMVC里,然后带动了SpringMVC的启动,启动成功后就可以对外提供服务了。

上下文路径

一个war包就是一个应用,Tomcat下面可以放多个war包,也就是Tomcat同时支持运行多个应用。那这多个应用之间不会起冲突吗?Tomcat不会搞混吗?

肯定是不会的,因为有一个叫做ContextPath(上下文路径)的东西存在,它就相当于应用的名字,来把它们分开,同时它也是URL的一部分,所以不同应用的URL也是不可能一样的。

同时,Tomcat还定义了类加载器,使一个应用不会加载到别的应用的类,这样保证了安全性。也就是说,即使两个应用中都定义了完全一样的类,那也不是同一个类。

一个Tomcat运行多个应用,如下图04:
技术图片

Servlet上下文

Tomcat接收到用户的请求,根据URL中的上下文路径和Servlet路径等信息选择出正确的应用里面的适合的Servlet去调用。

Tomcat既然要调用Servlet,那我们必须先把Servlet注册到Tomcat里才行。Tomcat会为每个应用创建一个上下文,称为Servlet上下文(ServletContext)。

每个应用都运行在自己的这个上下文中。如下图05:
技术图片

一个应用主要就是一些Servlet和Filter,所以只需把这些Servlet和Filter注册到这个ServletContext里就可以了。

传统上,Servlet和Filter的配置信息都会放在应用的web.xml文件中,所以Tomcat在启动时会去读这个文件内容,自动进行相关注册。

所以应用信息、上下文路径、Servlet信息和它对应的URL信息都会存储在已启动好的Tomcat内部,这样当一个请求过来后,根据请求的URL信息就匹配出适合的Servlet,然后Tomcat就会去调用它。

(END)

【聊透SpringMVC】抬高视角和追本溯源

标签:nta   网络   对象   and   类加载   应用信息   png   etc   目录   

原文地址:https://blog.51cto.com/15049788/2561495

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!