以TOMCAT为例,
Servlet API主要由两个Java包组成: javax.servlet和javax.servlet.http
在Servlet接口中定义了5个方法,其中3个方法都是由Servlet容器来调用的,容器会在Servlet的生命周期的不同阶段调用特定的方法:
GenericServlet抽象类为Servlet接口提供了通用实现,它与任何网络应用层协议无关。
GenericServlet除了实现了Servlet接口,还实现了ServletConfig接口和Serializable接口:
public abstract class GenericServlet
implements Servlet, ServletConfig, java.io.Serializable
GenericServlet类实现了Servlet接口中的init(ServletConfig config)初始化方法。GenericServlet类有一个ServletConfig类型的private成员变量,当Servlet容器调用GenericServlet的init(ServletConfig)方法时,该方法使得私有变量引用由容器传入的ServletConfig对象。GenericServlet类还定义了一个不带参数的init()方法,init(ServletConfig)方法会调用此方法。因此在子类中重写init时,最好重写init()方法,若重写Init(ServletConfig)方法,还需要先调用父类的init(ServletConfig)方法(super.init(config))。
GenericServlet类没有实现Servlet接口中的service()方法。service()方法是GenericServlet类中唯一的抽象方法,GenericServlet类的具体子类必须实现该方法。
GenericServlet类实现了Servlet接口的destroy()方法,但实际什么也没做。
GenericServlet类实现了ServletConfig接口的所有方法。
HttpServlet类是GenericServlet类的子类。HttpServlet类为Serlvet接口提供了与HTTP协议相关的通用实现,也就是说,HttpServlet对象适合运行在与客户端采用HTTP协议通信的Servlet容器或者Web容器中。
在我们自己开发的Java Web应用中,自定义的Servlet类一般都扩展自HttpServlet类。
HttpServlet类实现了Servlet接口中的service(ServletRequest , ServletResponse)方法,而该方法实际调用的是它的重载方法HttpServlet.service(HttpServletRequest, HttpServletResponse);
在上面的重载service()方法中,首先调用HttpServletRequest类型的参数的getMethod()方法,获得客户端的请求方法,然后根据该请求方式来调用匹配的服务方法;如果为GET方式,则调用doGet()方法,如果为POST方式,则调用doPost()方法。
HttpServlet类为所有的请求方式,提供了默认的实现doGet(),doPost(),doPut(),doDelete()方法;这些方法的默认实现都会向客户端返回一个错误。
对于HttpServlet类的具体子类,一般会针对客户端的特定请求方法,覆盖HttpServlet类中的相应的doXXX方法。如果客户端按照GET或POST方式请求访问HttpsServlet,并且这两种方法下,HttpServlet提供相同的服务,那么可以只实现doGet()方法,并且让doPost()方法调用doGet()方法。
ServletRequest表示来自客户端的请求;当Servlet容器接收到客户端要求访问特定Servlet的请求时,容器先解析客户端的原始请求数据,把它包装成一个ServletRequest对象。
ServletRequest接口提供了一系列用于读取客户端的请求数据的方法,例如:
HttpServletRequest接口是ServletRequest接口的子接口。
HttpServletRequest接口提供了用于读取HTTP请求中的相关信息的方法:
Servlet通过ServletResponse对象来生成响应结果。
ServletResponse接口定义了一系列与生成响应结果相关的方法,例如:
ServletResponse中响应正文的默认MIME类型是text/plain,即纯文本类型,而HttpServletResponse中响应正文的默认MIME类型为text/html,即HTML文档类型。
为了提高输出数据的效率,ServletOutputStream和PrintWriter首先把数据写到缓冲区内。当缓冲区内的数据被提交给客户后,ServletResponse的isComitted方法返回true。在以下几种情况下,缓冲区内的数据会被提交给客户,即数据被发送到客户端:
为了确保SerlvetOutputStream或PrintWriter输出的所有数据都会被提交给客户,比较安全的做法是在所有数据都输出完毕后,调用ServletOutputStream或PrintWriter的close()方法(Tomcat中,会自动关闭)。
如果要设置响应正文的MIME类型和字符编码,必须先调用ServletResponse对象的setContentType()和setCharacterEncoding()方法,然后再调用ServletResponse的getOutputStream()或getWriter()方法,提交缓冲区内的正文数据;只有满足这样的操作顺序,所做的设置才能生效。
HttpServletResponse接口提供了与HTTP协议相关的一些方法,Servlet可通过这些方法来设置HTTP响应头或向客户端写Cookie。
在HttpServletResponse接口中定义了一些代表HTTP响应状态代码的静态常量。
当Servlet容器初始化一个Servlet对象时,会为这个Servlet对象创建一个ServletConfig对象。
在Servlet对象中包含了Servlet的初始化参数信息。
ServletConfig接口中定义了以下方法:
HttpServlet类继承了GenericServlet类,而GenericServlet类实现了ServletConfig接口,因此HttpServlet或GenericServlet类及子类中都可以直接调用ServletConfig接口中的方法。
ServletContext是Servlet与Servlet容器之间直接通信的接口。
Servlet容器在启动一个Web应用时,会为它创建一个ServletContext对象。每个Web应用都有唯一的ServletContext对象,可以把ServletContext对象形象地理解为Web应用的总管家,同一个Web应用中的所有Servlet对象都共享一个ServletContext,Servlet对象可以通过其访问容器中的各种资源。
ServletContext接口提供的方法可以分为以下几种类型:
与Servlet主动关联的是三个类,分别是ServletConfig,ServletRequest和ServletResponse。这三个类都是通过容器传递给Servlet的;其中,ServletConfig是在Servlet初始化时传给Servlet的,后两个是在请求到达时调用Servlet传递过来的。
对于Request和Response,以TOMCAT为例,tomcat接到请求首先将会创建org.apache.coyote.Request和org.apache.coyote.Response,这两个类是Tomcat内部使用的描述一次请求和相应的信息类,它们是一个轻量级的类,作用就是在服务器接收到请求后,经过简单解析将这个请求快速分配给后续线程去处理。接下来当交给一个用户线程去处理这个请求时又创建org.apache.catalina.connector.Request和org.apache.catalina.connector.Response对象。这两个对象一直贯穿整个Servlet容器直到要传给Servlet,传给Servlet的是Request和Response的Facade类。
Request和Response的转变过程:
当用户从浏览器向服务器发起的一个请求通常会包含如下信息:
http://hostname:port/contextpath/servletpath
hostname和port用来与服务器建立TCP连接,后面的URL用来选择在服务器中哪个子容器服务用户的请求。
在Tomcat7中,这种映射工作由专门的一个类完成:org.apache.tomcat.util.http.mapper,这个类保存了tomcat的container容器中的所有子容器的信息。org.apache.catalina.connector.Request类在进入Container容器之前,Mapper将会根据这次请求的hostname和contextpath将host和context容器设置到Request的mappingData属性中,所以当Request进入container容器之前,对于它要访问哪个子容器就已经确定了。