servlet技术


Servlet的框架是由两个java包组成的:javax.servlet和javax.servlet.http.    

javax.servlet包含了支持普通协议无关的Servlet的类。

javax.servlet.http包括了对HTTP协议的特别支持。
  servlet的框架的核心是javax.servlet.Servlet接口,所有的Servlet都必须实现这一接口。在Servlet接口中定义了5个方法,其中有3个方法代表了Servlet的生命周期:
  (1)init方法,负责初始化Servlet对象
  (2)service方法,负责初始响应客户的请求
    (3)destroy方法,当Servlet对象退出生命周期时,负责释放占用的资源
Servlet技术



由上图可知,GenericServlet实现了Servlet接口,HttpServlet扩展了GenericServlet。用户开发自己的Servlet类时,扩展HttpServlet类即可。如果Servlet类扩展了HttpServlet类,通常不必实现service方法,因为HttpServlet类已经实现了service方法。在HttpServlet的service方法中,首先从HttpServletRequest对象中获取HTTP请求方式的信息,然后再根据请求方式调用相应的方法。
该方法的声明形式如下:
protected void service(HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException
在HttpServlet的service方法中,有两个参数:HttpServletRequest和HttpServletResponse,这两个类分别扩展了javax.servlet.ServletRequest和javax.servlet.ServletResponse接口。
ServletRequest接口:ServletRequest接口封装了客户请求信息,如客户请求方式、参数名和参数值、客户端正在使用的协议,以及发出客户请求的远程主机信息等。ServletRequest接口还为Servlet提供了直接以二进制数方式读取客户请求数据流的ServletInputStream。ServletRequest的子类可以为Servlet提供更多的与特定协议相关的数据
ServletRequest接口:ServletRequest接口为Servlet提供了返回响应结果的方法。它允许Servlet设置返回数据的长度和MIME类型,并且提供了输出流ServletOutputStream。ServletResponse子类可以提供更多和特定协议相关的方法。

HttpServlet能够根据客户发出的HTTP请求,生成相应的HTTP响应结果。HttpServlet首先必须读取HTTP请求的内容。Servlet容器负责创建HttpRequest对象,并把HTTP请求信息封装到HttpRequest对象中,这样通过调用HttpServletRequest的相关方法,就可以方便地读取HTTP请求中的任何一部分消息。



Servlet生命周期



阶段一:Servlet实现类的加载



(1)所有的web-server加载Servlet实现类的时候,都将搜索web-app根目录下WEB-INF目录的子目录lib和classes,在lib目录中搜索*.jar文件,在classes目录中搜索*.class文件;它将遍历WEB-INF目录下的web.xml配置文件,根据文件中的Servlet标签下Servlet-class子标签的内容加载相应的class文件。

(2)tomcat安装的根目录下的common目录的子目录lib中存放webapps目录下所有web-app的公共jar包,当web-app使用jar包时首先搜索本app中的lib,如果没有找到需要的jar包,将在common目录的lib中找jar包;

(3)web服务器启动时加载Servlet实现类的方法(配置WEB-INF目录下的web.xml)

在web.xml文件中与Servlet实现类相对应的Servlet标签中添加子标签,如:

<load-on-startup>1</load-on-startup>

标签内部的文本应是正整数,当多个Servlet实现类相对应的Servlet标签都添加了子标签时,根据该文本对应整数之的大小加载相应的Servlet实现类;整数值越小,加载顺序越靠前;值相等时,加载顺序由web-server决定。



阶段二:Servlet对象的创建与初始化



(1)大多数web-server会在客户端第一次访问服务器时加载Servlet实现类,创建对象并执行初始化方法,(如果设置服务器启动时加载,则服务器启动时创建对象并执行初始化方法,客户端第一次访问服务器时,直接进入service阶段执行service方法);以后每个客户端在发送请求就不会再调用init方法,也就是说它只能被调用一次。一个Servlet对象的初始化方法只执行一次;

(2)为Servlet对象设置初始化参数(配置WEB-INF目录下的web.xml)

1> 在web.xml文件中与Servlet实现类相对应的Servlet标签中添加子标签,如:

<init-param>

<param-name>参数名</param-name>

<param-value >参数值</param-value>

</init-param>

每对init-param标签只能设置一个初始化参数,如果要设置多个初始化参数,需重复以上四行代码;参数名一般都不能改,因为我们要在java程序中用到;参数值可以修改。

2> Servlet实现类中覆盖无参的init()方法,方法内部使用getInitParameter("参数名")获得相应的参数值,该方法在javax.Servlet.ServletConfig,javax.Servlet.GenericServlet两个类中都有定义,一般使用后者(即在Servlet实现类中直接使用getInitParameter("参数名")获得相应的参数值);

3> HttpServlet直接继承了GenericServlet类中init(ServletConfig)方法,GenericServlet类的init()方法有两种形式:常规初始化、由初始化参数控制的初始化

   public void init()throws ServletException{} //可以调用不带参数的方法

   public void init(ServletConfig config)throws ServletException{

   this.config=config;//初始化成员变量config

   init(); //这里直接调用了不带参数的init方法。

}



常规初始化:创建、载入在servlet生命周期内用到的一些数据,如为即将处理的请求建立数据库连接共享、将数据文件载入HashMap等



由初始化参数控制的初始化

   1. 通过向web.xml的servlet元素添加init-param子元素,可以指定初始化参数的名称和值

   2. 在servlet的init方法中,调用getServletConfig,获取ServletConfig对象的引用

   3. 以init方法的参数名称为参数,调用ServletConfig的getInitParameter方法,返回值就是init参数的值,或null——如果在web.xml文件中没有找到这个init参数。



init(ServletConfig)方法中第一行初始化了config成员变量,GenericServlet类中getInitParameter("参数名")方法返回的是getConfig().getInitParameter("参数名");当Servlet实现类中直接使用 getInitParameter("参数名"),由于没有初始化成员变量config,getConfig()将返回null;故会产生空指针异常,所以应该总是在第一行加上super.init(con)。



阶段三:Servlet对象根据客户端的请求提供service



(1)HttpServlet类继承自Servlet的实现类javax.Servlet.GenericServlet,HttpServlet类中覆盖的service()方法完成了由一个service方法向多个方法(doGet、doPost、doDelete等方法)转换的过程,细化了service方法的功能,doGet、doPost分别表示当客户端"method”属性设置为get和post时调用;HttpServlet的子类中只需要覆盖其中的一个功能方法;

(2)Service方法会在服务器被访问时调用,Servlet对象的生命周期中service方法可能被多次调用,由于web-server启动后,服务器中公开的部分资源将处于网络中,当网络中的不同主机(客户端)并发访问服务器中的同一资源,服务器将开设多个线程处理不同的请求,多线程同时处理同一对象时,有可能出现数据并发访问的错误。多线程同时处理同一变量时(如:对同一文件进行写操作),且有读写操作时,必须考虑是否加上同步(synchronized),同步添加时,不要添加范围过大,有可能使程序变为纯粹的单线程,大大削弱了系统性能;只需要做到多个线程安全的访问相同的对象就可以了;

在servlet中需要同步的有:成员变量,网络资源,文件,静态变量,数据库连接等,用到这些一定要考虑线程同步,安全的问题。



阶段四:Servlet对象的销毁(destroy()方法)



当程序中的Servlet对象不再使用时,web-server将有可能销毁该对象,不同的web-server销毁时机不同;一个Servlet对象的销毁(destroy()方法)只执行一次;

我们可以在这个方法里做关闭数据库,关闭流,终止后台线程等收尾工作。注意:不要把持久化的对象存入内存中,程序结束时统一转移到外部存储设备;因为在web-server异常退出(断电等因素引起)的时候,未能来得及转移数据,这样的话会造成数据丢失。



Servlet容器响应Web客户请求的步骤


1:Web客户向Servlet容器发出HTTP请求;
2:Servlet容器解析Web客户的HTTP请求;
3:Servlet容器创建一个HttpRequset对象,在这个对象中封装了HTTP请求信息;
4:Servlet容器创建一个HttpResponse对象;
5:Servlet容器调用HttpServlet的service方法,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象;
6:HttpServlet调用HttpResponse的有关方法,获取HTTP请求信息
7:HttpServlet调用HttpResponse的有关方法,生成响应数据
8:Servlet容器把HttpServlet的响应结果传给Web客户



SERVLET API中forward() 与redirect()的区别?


答:前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量使用forward()方法,并且,这样也有助于隐藏实际的链接。在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用sendRedirect()方法。

你可能感兴趣的:(servlet)