Servlet详解
Servlet
Servlet
是Sun公司提供的用于web开发的接口, 我们一般把实现了Servlet
接口的程序称为Servlet
程序Servlet
应该由web服务器调用(比如通过配置web.xml
), 自己不能独立运行Servlet
接口有两个实现类HttpServlet --> GenericServlet
,HttpServlet
重写了service
方法, 根据请求方式自动调用doGet
或doPost
方法, 我们一般继承这个类, 重写doGet、doPost
即可.
Servlet生命周期
![Servlet生命周期](/assets/servlet-DhHXt9CX.png)
如图:
- 图中画出的是第一次请求
Servlet
的情况, 若对应的Servlet
对象还没被创建, 则创建Servlet
对象 Servlet
对象只初始化一次, 只会执行一次init()
方法,Servlet
初始化好之后, 新请求将直接到第5步- 第2步中解析出的应用对应
getContextPath
, 资源对应getServletPath
- 图中没画出
Servlet
的消亡,Servlet
对象被创建后常驻内存, 继续为其他请求服务; web应用停止前调用Servlet
的destroy()
方法,Servlet
生命周期才结束
Servlet配置
- 上面的
Servlet
是有第一个请求时被创建, 可以在web.xml
中通过<load-on-startup>
元素指定在web容器启动时就直接初始化Servlet
Servlet
所映射的URL由<servlet-mapping>
里的<url-pattern>
指定, 它只有两个固定格式:*.扩展名
, 如:*.do
- 以
/
开头(并以/*
结尾), 如:/abc
,/abc/*
- URL映射以最精确的为准, 请求
/abc
时, 映射/abc
和/abc/*
都可以匹配, 但优先选择/abc
; 请求/a.do
时,/*
和*.do
都可以匹配, 但优先选择/*
(即/*
优先级高于*.do
)
ServletConfig
在web.xml
中可以使用<init-param>
标签为Servlet
配置一些参数. HttpServlet
类也实现了ServletConfig
接口, 在创建Servlet
对象时先把参数封装到ServletConfig
对象中, 在调用Servlet
的init
方法时把ServletConfig
对象传给Servlet
.
在Servlet
类中, 我们可以获取ServletConfig
中的参数
ServletConfig config = this.getServletConfig(); // 这个方法继承自GenericServlet
String value = config.getInitParameter("charset"); // 这可获取我们配置的参数
ServletContext
ServletContext
表示应用的上下文, 在Web容器在启动时, 会为每个Web应用程序都创建一个对应的ServletContext
对象, 一个应用只有一个ServletContext
对象, 被所有的Servlet
共享.
ServletContext
的属性可以通过web.xml
中的<context-param>
标签来指定, 在程序中可以这样获取这些属性:
// ServletConfig 里维护了 ServletContext 对象的引用
ServletContext context = this.getServletConfig().getServletContext();
// 因为 Servlet类实现了 ServletConfig 接口, 所以也可以直接获取
ServletContext context1 = this.getServletContext();
// 获取属性
context.getAttribute("data");
// 获取 <display-name> 标签配置的应用名
context.getServletContextName();
Filter
Servlet API
中提供了一个Filter
接口, 称为过滤器, 所有的请求要先经过过滤器. web服务器在调用Servlet
的service()
方法之前会调用Filter
的doFilter()
方法.
web服务器把所有的Filter
按注册顺序组成一个filterChain
, 在调用Filter
的doFilter()
方法时, 会传递filterChain
对象进来. filterChain
也有个doFilter
方法, 当调用filterChain.doFilter()
时, web服务器会检查filterChain
中是否还有filter
, 如果有, 则调用下一个filter
.
Filter生命周期
Filter
的创建和销毁由web服务器负责. web服务器启动时创建Filter
实例对象, 并调用其init
方法, 完成对象的初始化, 为用户请求作好拦截的准备. Filter
对象只创建一次, init
方法只执行一次. Filter
也有初始化参数, 被封装到FilterConfig
中, 它有个方法getServletContext()
可获取ServletContext
装饰器模式(decorator)
在Servlet API
中体现了一种设计模式: 装饰器模式
装饰器模式的实现步骤:
- 先看需要被增强对象实现了什么接口或继承了什么父类, 编写一个类也去继承这些接口或父类
- 内部定义一个变量, 类型为被包装类的类型, 并提供一个构造函数用于接收被包装对象
- 覆盖需要增强的方法, 添加增强内容
- 实现接口中其他方法, 调用被包装对象的对应方法.
Servlet API
提供了一个HttpServletRequestWrapper
类, 该类就是采用装饰器模式对HttpServletRequest
进行了增强(实际上在内部仅调用了一下所包装的对象的对应方法).
Listener
全称是事件监听器EventListener
, 全类名是java.util.EventListener
, Servlet API
中的监听器也是继承这个接口.
监听器是典型的 观察者模式 , 使用监听器要了解三个概念:
- 事件源: 就是被监听的对象
- 事件对象: 就是被监听的对象发生的动作, 封装成了一个事件对象. 比如增加了一个属性
- 监听器: 对事件源发生的动作做出反应的对象. 由开发人员编写, 在事件监听器中, 可通过事件对象拿到事件源, 从而对事件源上的操作进行处理.
Servlet监听器
Servlet
中的监听器不是直接注册在事件源上的, 而是由由WEB容器负责注册.
在Servlet
规范中定义了多种类型的监听器, 它们用于监听的事件源分别为ServletContext
, HttpSession
和ServletRequest
这三个对象.
根据监听的类型不同, 又可分为:
- 监听事件源对象创建和销毁的事件监听器, 如:
ServletContextListener, HttpSessionListener, ServletRequestListener
. - 监听事件源对象属性添加和删除的事件监听器, 如:
ServletContextAttributeListener, HttpSessionAttributeListener, ServletRequestAttributeListener
. - 监听绑定到
HttpSession
中的对象的状态的事件监听器, 如:HttpSessionBindingListener, HttpSessionActivationListener
, 这俩监听器比较特殊, 不需要在web.xml
中进行注册