Servlet与SpringMVC
Servlet
Java Servlet 技术简称 Servlet 技术,是 Java 开发 Web 应用的底层技术。由 Sun 公司于 1996 年发布,用来代替 CGU—-当时生成 Web 动态内容的主流技术。CGI 的问题是每一个 WEB 请求都需要重新启动一个进程来处理。创建进程需要消耗不少 CPU 周期,导致难以编写刻苦鏖战的 CGI 程序,而 Servlet 在创建后(处理第一个请求时)就一直保存在内存中,这就比 CGI 有着更好的性能。
Servlet 是一个 Java 程序,一个 servlet 应用有一个或多个 Servlet 程序。JSP 页面会被转换和编译成 servlet 程序。
Servlet 程序无法独立运行,必须运行在 Servlet 容器中。Servlet 容器将用户的请求床底给 servlet 应用,并将结果返回给用户。由于大部分 Servlet 用用都包含多个 JSP 页面,因此更准确地说是“Servlet/JSP 应用”。
Servlet/JSP 容器是一个可以同时处理 Servlet 和静态内容的 Web 容器。过去,由于通常认为 HTTP 服务器比 Servlet/JSP 容器更加可靠,因此人们习惯将 servlet 容器当做 HTTP 服务器的一个模块,这种模式下,HTTP 服务器用来处理静态资源,Servlet 容器则负责生成动态内容。
例子
1 | public class HelloServlet extends HttpServlet { |
我们可以看见,这个 HelloServlet 继承了 HTTPServlet 类,主要有 init()、doGet()、doPost()、destroy()四个方法。我们在浏览器中分别用 get 和 post 访问这个 servlet。
我们可以看到,这就是上文我们编写的 doGet 方法中的 Html 生成的页面。
Servlet 前世今生
一个 web 请求过程:
- 接受请求
- 处理请求
- 相应请求
web 服务器负责接受请求和相应请求,如果是静态资源那么 web 服务器就够用了。如果是动态资源就要处理请求,这时候就需要 servlet 了。 servlet 专门用来处理请求,编写业务逻辑。后来三层架构出现了,servlet 就把一些任务分担到 servier 和 dao,形成了 servlet(contrller)+service+dao。servlet 本身不擅长往浏览器输出 HTML 页面,所以出现了 JSP。
等 Spring 家族出现后,Servlet 开始退居幕后,取而代之的是 SpringMVC。SpringMVC 的核心组件 DispatcherServlet 其实本质就是一个 Servlet。但它已经自立门户,在原来 HTTPServlet 的基础上,又封装了一条逻辑。
Servlet 是 J2EE 规范中的一种,主要是为了扩展 java 作为 web 服务的功能,事实上,servlet 就是一个 Java 接口。
Servlet 与 SpringMVC
参考连接:https://zhuanlan.zhihu.com/p/65658315
ServletContext
ServletContext 对象的作用是在整个 Web 应用的动态资源(Servlet/JSP)之间共享数据。例如在 AServlet 中向 ServletContext 对象保存一个值,然后在 BServlet 中就可以获取这个值。
共享数据
这种用来装载共享数据的对象,在 JavaWeb 中共有 4 个,而且更习惯被成为“域对象”:
- ServletContext 域(Servlet 间共享数据)
- Session 域(一次会话间共享数据,也可以理解为多次请求间共享数据)
- Request 域(同一次请求共享数据)
- Page 域(JSP 页面内共享数据)
它们都可以看做是 map,都有 getAttribute()/setAttribute()方法。
ServletContext 的方法
所以,获取 ServletContext 的方法共 5 种(page 域这里不考虑,JSP 太少用了):
- ServletConfig#getServletContext();
- GenericServlet#getServletContext();
- HttpSession#getServletContext();
- HttpServletRequest#getServletContext();
- ServletContextEvent#getServletContext();
Filter 过滤器
Filter 更详细的拦截其实是这样:
最外层那个圈,可以理解成 ServletContext,FORWARD/INCLUDE 这些都是内部请求。如果在 web.xml 中配置 Filter 时 4 种拦截方式全配上,那么服务器内部的分发跳转都会被过滤。下图中灰色的墙就是 fliter。红色字代表各种请求方式,FORWARD 和 INCLUDE 的位置相同。
映射器
对于静态资源,Tomcat 最后会交由一个叫做 DefaultServlet 的类来处理
对于 Servlet ,Tomcat 最后会交由一个叫做 InvokerServlet 的类来处理
对于 JSP,Tomcat 最后会交由一个叫做 JspServlet 的类来处理
DispatcherServlet 与 SpringMVC
tomcat 是一个 Servlet 容器,这个容器内可以存在多个 servlet,处理不同的请求。
加入 springmvc,它提供了一个 Servlet,可以处理.do 结尾的请求,还有静态资源的请求和其它请求。如果,我们为 springmvc 在 web.xml 配置的映射 url 为/*则代表所有请求都要走 springmvc,tomcat 中的 DefaultServlet 和 JSPServlet 都无法得到请求。因为这个两个 servlet 是在 tomcat 的 conf/web.xml 中配置的,这个 web.xml 的配置会被各个应用自己的 web.xml 覆盖,最终 tomcat 按照应用定义的 web.xml 来做映射。
SpringMVC 的核心控制器叫 DispatcherServlet,映射原理和我们上面山寨版的一样,因为本质还是个 Servlet。但 SpringMVC 提供了一个标签,解决上面/无法读取静态资源的问题:
1 | <!-- 静态资源处理 css js imgs --> |
其他的我也不说了,一张图,大家体会一下 DispatcherServlet 与 SpringMVC 到底是什么关系:
DispatcherServlet 确实是一个 Servlet,但它只是入口,SpringMVC 要比想象的庞大。DispatcherServlet 只是 Springmvc 的一个入口,Springmvc 内部是十分复杂的。