从 Servlet 到 Spring Boot
大家好, 我是废材, 好久没输出文章了(废材最近有点不务正业), 前段时间废材在一个技术群里看到一个人在讲他的面试经历, 有句话我印象很深刻, 他说这个公司用的技术太老了,还在用过滤器和拦截器这些东西. 看到这个废材心里一颤, What??? 我老了, 不不不,不对, 不是我老了.是我用的技术太老了? 作为一个技术渣渣, 废材也是要上进的呀. 废材可以进入java开发就使用Spring, 我也喜欢spring框架给我们的开发带来的便利,但是不知道大家是否跟废材一样好奇, 这些东西为什么这么设计, 网上经常看到的Servlet又是什么, HttpServletRequest和HttpServletResponse又从哪来的?最近废材就恶补了一下相关的知识, 现在把结果跟大家分享一下.
在正式的进入Servlet的学习之前, 我们先来了解几个基本名词: Web Server, Web Container, Servlet Container, Servlet.
什么是Web Server
web server使用HTTP协议进行数据传输, 一个简单的使用场景是当我们在浏览器地址栏输入一个URL, 如:www.programcreek.com/static.html, web Server便会返回一个页面给浏览器,用户就可以看到这个页面:
Servlet和 Web Container
如果只有web Server, 用户只能访问静态资源,但是我们现在在浏览器访问时都可以自己在页面输入, 然后web server根据我们的输入返回相应的内容,这个工作就是由Web Container来完成的,即Web容器,有的资料中也称为Servlet容器。而Servlet就是真正的负责请求、响应的。
Servlet Container 和 Web Server如何处理一个请求
认识了Web Server和Web Container之后,我们来看看他们是如何配合处理一个请求的。我画了个简单的流程图:
1、web服务器接受到http请求。
2、web 服务器将请求转由servlet容器处理,web容器会剖析Http请求的内容, 创建各种对象(如HttpServletRequest, HttpServletResponse, HttpSession等)。
3、Web容器由请求的URI决定使用哪个Servlet来处理请求。
4、Servlet根据请求对象(HttpServletRequest)的信息决定如何处理, 通过响应对象(HttpServletResponse)来创建响应。
5、web服务器将响应对象转换为Http响应传回给浏览器。
Servlet
那Servlet到底是什么呢?前面我们Servlet容器是用来管理servlet的, 那我们就从Web容器入手,来学习一下Servlet,我们平时在创建Spring boot项目的时候默认会使用Tomcat作为web容器,那我们就去看看tomcat包里都有啥,如下图是我的一个spring boot项目中的Tomcat包如下:
从这个包中我们可以看到Servlet是javax.servlet包下一个接口,它定义了servlet三个生命周期方法:
init()方法在Servlet初始化时会被调用, 并传入了ServletConfig用于获取初始化参数。
service()方法在每个请求到来时会被调用,并且每个请求都是在单独的线程中。由service()方法来解析决定调用哪一个具体的方法来处理请求。
destroy()方法在servlet被销毁时调用,用于释放资源。
有了接口,那实现呢?我们有不同的Http方法, 比如get、post、delete等等这些是怎么处理的呢,让我们继续找,这时你会看到两个抽象的实现类GenericServlet和HttpServlet,他们之间具体的类图关系如下:
由上图可以看到GenericServlet并没有规范任何与http相关的方法,而是由继承它的HttpServlet定义。而且观察这个包的结构可以发现,与Servlet定义相关的接口或类是在javax.servlet包下,而与Http相关的类或接口是定义在javax.servlet.http包下,如HttpServlet,以及我们常用的HttpServletRequest 和HttpServletResponse.
现在我们知道HTTP相关的定义是在HttpServlet中,而且service()方法是具体处理每个请求的,那我们就来看看HttpServlet中的Service()方法的定义吧:
这些是不是一下子就清晰了, 我们的请求是怎么工作的, 怎么就调用了doGet() 或者是doPost() 方法。
servletConfig和ServletContext
在前面的讲解中,不知道大家有没有注意到两个抽象实现类中有两个对象ServletConfig和ServletContext, 它们是做什么用的呢?ServletConfig相当于Servlet设置信息代表对象,它提供了两个方法getInitParameter()、getInitParameterNames(),用于获取设置Servlet时的初始参数。ServletContext定义了运行Servlet的应用程序的环境的一些行为,即我们常说的上下文, 可以通过ServletContext获得所请求资源的URI,设置和存储属性、应用程序初始化参数,甚至动态的设置Servlet实例。ServletContext是在整个Web容器启动时创建的,是这个应用程序的代表, 所有的Servlet之间可以共享, 并且设置给了ServletConfig, 所有可以通过ServletConfig获得。这些简单了解就好, 毕竟我们一般不会真的自己去实现一个Servlet。至此Servlet相关的内容我们就介绍完了,再额外多提一点的是Web容器除了管理Servlet容器之外,还会用于管理监听器或过滤器, 如果对HttpServletRequest、HttpSession、ServletContext对象在生成、销毁或相关属性设置的时间点上想额外做点什么,可以使用监听器。过滤器是介于Servlet之前,可拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。监听器我们很少用到, 我们不再赘述。过滤器我会在后面的分享中详解解说。
Spring MVC 和Spring Boot
说了那么多,终于可以进入我们今天的主题了,为什么要学习Servlet,不知道看到现在大家会想到什么?
废材想到的是Spring MVC的DispatchServlet,相信初学Spring时大家一定看过类似于下面这样的图:该图展示了Spring MVC如何处理一个请求, 相信大家比废材熟悉这个流程,但是这个DispatchServlet和Servlet有什么关系吗?让我们扒一扒源码看看:
这下是不是瞬间清楚了,原来DispatchSevlet本质就是一个Servlet呀,顺着分析HttpServlet的思路, 我们来看看, DispatchServlet中对service()方法干了什么:
是不是熟悉的一幕又出现了,剩下的就不在本篇文章的范围了, 感兴趣的小伙伴可以自己去翻翻源码读一读。
最后我们提一下Spring Boot,所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。
最后的Spring 和Spring Boot我们没有深入,废材只是想表达技术会过时,但有时本质是不变的,真正掌握了本质才能举一反三,在技术飞速发展的今天,让我们都沉下来慢慢研究。
评论 (2 条评论)