JavaWeb 三大器--Listener、Filter 和Interceptor 总结
说明:web.xml的加载顺序是:【Context-Param】->【Listener】->【Filter】->【Servlet】,而同个类型之间的实际程序调用的时候的顺序是根据对应的Mapping的顺序进行调用。
详细介绍:web.xml加载顺序与web.xml常用节点解析
转自:https://www.cnblogs.com/hellovoyager1/p/9152292.html
一、背景
这段时间因为工作不忙,所以有时间来总结整理一下之前遇到的一些问题。在之前项目开发过程中碰到过关于拦截器、过滤器之类的问题(发现自己基础真的薄弱,不过没关系知识一点一滴积累),索性就记录下来。由于笔者知识水平有限,如有不对的地方欢迎批评指正。
二、概念
在讲解三大器之前,我们需要对Servlet 有所了解,因为这个通常是我们在接触Javaweb 时最先了解到的知识点。
1. Servlet
Servlet 是sun 公司提供的一门用于开发动态web 资源的技术,主要功能在于交互式地浏览和修改数据,生成动态Web 页面,我们实际开发应用中,一般不需要去研究Http 协议,只要扩展servlet 接口,即可实现web 服务器应用程序的开发。通俗来讲,就是这个技术可以实现一个由客户端发起请求-->服务器端处理-->客户端得到响应的功能。额。。。还不是很有概念,那Servlet 得生命周期总有印象吧?
这里说个题外话,提到Servlet 的生命周期,首先,这个在面试时经常被问到。
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程(三个重要方法):
①init () 方法进行初始化:
在Servlet的生命周期中,仅执行一次init()方法,它是在服务器装入Servlet时执行的,可以配置服务器,以在启动服务器或客户机首次访问Servlet 时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init();
②Servlet 调用 service() 方法来处理客户端的请求:
它是Servlet的核心,每当一个客户请求一个HttpServlet 对象,该对象的Service() 方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet 中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
③Servlet 通过调用 destroy() 方法终止(结束):
仅执行一次,在服务器端停止且卸载Servlet 时执行该方法,有点类似于C++ delete 方法。一个Servlet 在运行service() 方法时可能会产生其他的线程,因此需要确认在调用destroy() 方法时,这些线程已经终止或完成。
Servlet 的生命周期的话还需要加上在init() 之前有一个加载和实例化Servlet(反射机制)的过程。
整个过程大概是这样的:
其次,还记得在大三那会去实习,组长给我们讲解Java 知识的时候就有提到过Servlet。记得当时是做一个登录跳转的功能,写一个Java 类,实现Servlet 接口,然后写doGet() 和doPost() 方法,因为这里要处理乱码来着,搞了半天。。。至此,这两点大概是我对Servlet 的最深印象了吧。那么,之后的工作中为什么仿佛彻底与这东西无缘了一样。时至今日,再次提起这个东西才知道一直有在用,只是自己不知道而已。
回到正题,现在我们的Servlet 哪里去了呢?没错,它没有消失,而是在我们的web.xml 文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!-- spring mvc servlet --> <servlet> <description>spring mvc servlet</description> <servlet-name>springMvc</servlet-name> <servlet- class >org.springframework.web.servlet.DispatcherServlet</servlet- class > <init-param> <description>spring mvc 配置文件</description> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup> 1 </load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>*. do </url-pattern> </servlet-mapping> |
通过这种方式我们就实现对*.do 这样的请求进行统一处理,通常我们也把实现了servlet 接口的java 程序,称之为Servlet。如果换成以前的写法,就是这样的:
Servlet 类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/** * 用户登录校验 * Servlet implementation class LoginServlet */ @WebServlet ( "/LoginServlet" ) public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; public LoginServlet() { super (); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //String username = request.getParameter("username"); //String password = request.getParameter("password"); //... // success doGet(request, response); } } |
web.xml 配置:
1
2
3
4
5
6
7
8
9
10
11
12
|
<servlet> <!-- Servlet的注册名称 --> <servlet-name>LoginServlet</servlet-name> <!-- Servlet的完整类名 --> <servlet- class >com.github.servlet.LoginServlet</servlet- class > </servlet> <servlet-mapping> <!-- Servlet的注册名称 --> <servlet-name>LoginServlet</servlet-name> <!-- Servlet的对外访问路径 --> <url-pattern>/servlet/loginServlet</url-pattern> </servlet-mapping> |
访问路径
看到这里终于明白,现在每天都在用的DispatcherServlet 正是以前所接触过得Servlet。进一步跟踪DispatcherServlet 发现果然,他确实是实现了HttpServlet 接口
2.Listener
监听器,从字面上可以看出listener 主要用来监听时用。通过listener 可以监听web 服务器中某一个执行动作,并根据其要求作出相应的响应。通俗的语言说就是在application,session,request三个对象创建消亡或者往其中添加修改删除属性时自动执行代码的功能组件。
3.Filter
过滤器,是一个可以复用的代码片段,可以用来转换HTTP请求、响应和头信息。Filter不像Servlet,它不能产生一个请求或者响应,它只是修改对某一资源的请求,或者修改从某一的响应。
4.Interceptor
拦截器,是在面向切面编程的,就是在你的service 或者一个方法,前调用一个方法,或者在方法后调用一个方法。比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。
5.配置方式
servlet、filter、listener是配置到web.xml中,interceptor不配置到web.xml中,struts的拦截器配置到struts.xml中,spring的拦截器配置到spring.xml中。
三、生命周期
1、servlet:servlet的生命周期始于它被装入web服务器的内存时,并在web服务器终止或重新装入servlet时结束。servlet一旦被装入web服务器,一般不会从web服务器内存中删除,直至web服务器关闭或重新结束。
(1)、装入:启动服务器时加载Servlet的实例;
(2)、初始化:web服务器启动时或web服务器接收到请求时,或者两者之间的某个时刻启动。初始化工作有init()方法负责执行完成;
(3)、调用:从第一次到以后的多次访问,都是只调用doGet()或doPost()方法;
(4)、销毁:停止服务器时调用destroy()方法,销毁实例。
2、filter:(一定要实现javax.servlet包的Filter接口的三个方法init()、doFilter()、destroy(),空实现也行)
(1)、启动服务器时加载过滤器的实例,并调用init()方法来初始化实例;
(2)、每一次请求时都只调用方法doFilter()进行处理;
(3)、停止服务器时调用destroy()方法,销毁实例。
3、listener:类似于servlet和filter
web.xml 的加载顺序是:context- param -> listener -> filter -> servlet
4、interceptor:以struts的拦截器为例,加载了struts.xml以后,初始化相应拦截器。当action请求来时调用intercept方法,服务器停止销毁interceptor。
四、总结
三大器对比:
ps:
1.平时所用的框架(Spring、Structs2等)其实都是基于JavaWeb 这四个知识点来做文章的,如果对原始的JavaWeb 不是很了解,那么在理解这些框架(框架是大牛们对原始JavaWeb进行封装的结果,没有原始JavaWeb开发基础是很难真正学会框架的)上只能是知道是这样做,而不知道为什么要这样做,这种对框架的理解也只是存在表面上,稍微深入一点就得懵逼。
2.自己在实际工作中很多东西做完了就没了,还是缺少一种独立思考的能力。求学,不应该只是不求甚解,更应该有一种知之者不如好之者,好之者不如乐之者的心态,主动学习。
3.站在巨人的肩膀,能看的更远。