摘录:《深入体验Java Web开发内幕--核心基础》。
一个Servlet程序就是一个实现了特殊接口的Java类,它由支持Servlet的Web服务器(具有Servlet引擎)调用和启动运行。一个Servlet程序负责处理它对应的一个或一组URL地址的访问请求,并用于接受客户端发出的请求信息和产生响应内容。
一个Servlet程序就是一个在Web服务器端运行的调用了Servlet API的Java类。servlet-api.jar。一些通用的Servlet API类和接口包含在javax.servlet包中,专用于Http协议的Servlet类和接口都包含在javax.servlet.http包中。还有javax.servlet.jsp和javax.servlet.jsp.tagext包。
一个Java类只要继承了GenericServlet或HttpServlet,它就是一个Servlet。
注册Servlet:
-----------------
<servlet>
<servlet-name>...</servlet-name>
<servlet-class>...</servlet-class>
</servlet>
映射Servlet
------------------
<servlet-mapping>
<servlet-name>...</servlet-name>
<url-pattern>...</url-pattern>
</servlet-mapping>
Servlet程序不能设置为Web应用程序的目录默认网页文档。
Servlet激活器
-----------------
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
缺省Servlet
-----------------
如果某个Servlet的映射路径仅仅是一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet,凡是在web.xml中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理。org.apache.catalina.servlets.DefaultServlet就是Tomcat的缺省Servlet。
当访问Tomcat服务器中的某个静态HTML文件或图片时,实际上是在访问这个缺省Servlet,而这个缺省Servlet的处理方式通常是把静态资源中的内容按字节原封不动地读出来,再传递给客户端,并生成一些响应消息头字段。
Servlet程序只能与Servlet引擎打交道,它并不与Web服务器和客户端进行任何直接的交互。在Servlet中可以将HTTP请求/响应的状态信息保存到Servlet引擎中,从而实现Web浏览器和Web服务器之间的有状态会话。
Servlet运行过程
--------------------
1. 接收到访问某个Servlet的HTTP请求后,Servlet引擎首先检查是否已创建该Servlet的实例对象,如果没有,则2。否则则4。
2. 装载并创建Servlet的一个实例对象。
3. 调用Servlet对象的init()方法,执行Servlet的一些初始化工作。
4. 创建一个用于HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
5. 在一个Web应用被停止或重新启动前,Servlet引擎将卸载其中运行的Servlet。
在Servlet的整个生命周期中,Servlet只被初始化一次,而对一个Servlet的每次访问都会导致Servlet引擎调用一次Servlet的service()方法。
如果对某个已经装载的Servlet进行了修改,除非重新启动Tomcat,否则客户端访问的Servlet实例对象还是修改以前的Servlet版本。这是因为Servet在服务器的运行期间只会被加载一次。可在<Context>元素中设置reloadable属性。即使设置了,Tomcat也是每隔一段时间才执行一次Servlet的修改检查,所以应该多刷新几次或者稍等片刻后再访问。
Servlet的线程
------------------
Servlet引擎采用多线程模式运行,为并发的每个访问请求都预备一个独立的线程来进行响应。
ServletConfig接口
======================
Servlet引擎需要将表示Servlet容器的对象传递给Servlet,另外在web.xml文件中的初始化参数也需要传递给该Servlet。Servlet引擎将代表Servlet容器的对象和Servlet的配置参数信息一并封装到一个称为ServletConfig的对象中,并在初始化Servlet实例对象时传递给该Servlet。init(ServletConfig config)方法将ServletConfig对象传递给Servlet。
getInitParameterNames
---------------------------------
返回一个Enumeration集合的对象,该对象中包含在web.xml中为当前Servlet设置的所有初始化参数的名称。下面的例子返回包含连个元素"firstname"和"lastname"的Enumeration集合对象。
<servlet>
<init-param>
<param-name>firstname</param-name>
<param-value>zhang</param-value>
</init-param>
<init-param>
<param-name>last</param-name>
<param-value>yong</param-value>
</init-param>
</servlet>
getInitParameter
----------------------
getInitParameter("firstname")返回"zhang"。
getServletName
----------------------
返回在web.xml中的注册名称。
getServletContext
------------------------
在Servlet程序中,每个Web应用程序都用一个各自的ServletContext对象来表示,ServletConfig中包含了ServletContext的引用。
GenericServlet类实现ServletConfig接口
------------------------------------------------------
不用先调用getServletConfig()再调用getServletName(),而是可以直接调用getServletName()。
PrintWriter out = response.getWriter();
Enumeration e = getInitParameterNames();
while (e.hasMoreElements())
{
String key = (String)e.nextElement();
String value = getInitParemeter(key);
out.println(key + "=" + value + "<br>");
}
ServletContext context = getServletContext();
String path = context.getRealPath("/");
GenericServlet与HttpServlet类
==============================
浏览器缓存内幕与getLastModified方法
====================================
响应消息中的Last-Modified头字段可用于指定响应内容的最后更新时间,当客户机缓存此文档内容后,它在以后的请求消息中将根据Last-Modified字段制定的时间来生成If-Modified-Since请求字段,以指出缓存文档的最后更新时间。如果自从If-Modified-Since指定的时间以来,网页内容没有变化,服务器将返回一个304(Not Modified)状态码。
对于动态网页,浏览器将根据响应消息中是否包含Last-Modified头字段来进行处理,如果没有,则每次访问此页面的时候都向服务器发出请求。
getLastModified()方法的返回值可以影响浏览器如何处理和利用缓存内容。
protected long getLastModified(HttpServletRequest req); 其中返回值代表Servlet当前输出的响应内容的修改时间。
1. 当getLastModified方法返回一个负数时,不管请求消息中的情况怎样,service方法都将直接调用doGet方法来生成响应内容。
2. 当getLastModified方法返回一个正数,且请求消息中没有包含If-Modified-Since,或者请求消息的If-Modified-Since中的时间值比getLastModified方法返回的时间值旧时,service调用doGet方法。
3. getLastModified返回值与If-Modified-Since时间值相同或更新时,不调用doGet()。
ServletContext接口
====================
每个Web应用程序都是一个独立的Servlet容器,每个Web应用程序分别用一个ServletContext对象来表示。ServletContext对象被包含在ServletConfig对象中。ServletConfig.getServletContext()可返回一个引用。
server.xml和web.xml文件中都可以为某个Web应用程序设置若干初始化参数,ServletContext接口中定义了获取这些初始化参数信息的一些方法。为Web应用程序设置初始化参数的好处在于不需要修改Servlet源程序,就可以改变整个Web应用程序范围内的一些参数信息。ServletContext.getInitParameterNames(),ServletContext.getInitParameter()。前面提到的ServletConfig也有类似的方法。
<context-param>
<param-name>..</param-name>
<param-value>..</param-value>
</context-param>
application域范围的属性
--------------------------------
由于一个Web应用程序中的所有Servlet都共享一个ServletContext对象,所以这个对象有被称为application对象。application域范围的属性可以被当作该Web应用程序范围的全局变量使用。ServletContext中定义了4个分别用于增加、删除、访问application域范围内的属性方法:
getAttributeNames
getAttribute
removeAttribute
setAttribute
访问资源文件
------------------
ServletContext接口还定义了一些用于访问Web应用程序的内部资源文件的方法。
getResourcePaths
getResource
getResourceAsStream
import java.servlet.*;
import java.servlet.http.*;
import java.util.Properties;
public class FileAccessServlet extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response) {
PrintWriter out = response.getWriter();
FileInputStream fis = new FileInputStream("my.properties");
Properties props = new Properties();
props.load(fis);
out.println("database=" + props.getProperty("database"));
}
}
Web应用程序之间的访问
---------------------------------
getServletContext().getContext().getRealPath();