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

Posted Java3y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聊透SpringMVC抬高视角和追本溯源相关的知识,希望对你有一定的参考价值。

                                                   本文公众号来源:编程新说
作者:编程新说李新杰
本文已收录至我的 GitHub


抬高视角


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

请看一个高层次的请求处理过程,如下图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】抬高视角和追本溯源


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

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

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


在类的上面通过 @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:

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


Servlet上下文


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

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

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

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


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

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

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


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

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


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

以上是关于聊透SpringMVC抬高视角和追本溯源的主要内容,如果未能解决你的问题,请参考以下文章

聊透SpringMVC虾皮java开发面经

一文聊透 Dubbo 优雅上线

一文聊透binlogredo logundo log

一文入魂!聊透分布式系统一致性!

聊透SpringMVCkafkassl认证

聊透SpringMVCjava技术经理岗位职责