欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Servlet基础

程序员文章站 2022-06-03 09:14:14
...

Servlet调用图

Servlet基础

 

 

Servlet的运行过程

1Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。

2装载并创建该Servlet的一个实例对象。

3调用Servlet实例对象的init()方法。

4创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。

5WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法

Servlet的实现方式

1//实现Servlet接口来开发Servlet程序
public class Demo11 implements Servlet {
	public void destroy() {
	}

	public ServletConfig getServletConfig() {
		return null;
	}

	public String getServletInfo() {
		return null;
	}

	public void init(ServletConfig arg0) throws ServletException {
	}

	public void service(ServletRequest request, ServletResponse response) {
	}
}


2//扩展GenericServlet实现Servlet程序
public class Demo12 extends GenericServlet {
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
	}
}

3//扩展 HttpServlet实现Servlet程序
public class Demo13 extends HttpServlet {
	// 如果浏览器是以get方式提交,则覆写doGet()方法
	public void doGet(HttpServletRequest request, HttpServletResponse response){
	}
}

 

 

Servlet工作原理和生命周期
  1)当浏览器第一次访问Servlet时,服务器会根据浏览器访问的路径,例如/Demo2,在web.xml文件中找到该Servlet的全路径,
     进行反射。
  2)调用init()为Servlet作初始化工作
  3)调用doXxxxx()为浏览器响应
  4)如果浏览器再次访问相同的Servlet,直实现从服务端维护的Servlet实例集合中取得对应的实现,为浏览器响应
  5)同一个Servlet实例,在服务端只有一个
  6)服务器在决定销毁Servlet实例之前,调用destory()方法,每个Servlet实例只会调用一次,在重新部署情况下会发生destory

 

public class Demo14 extends HttpServlet {
	public Demo14(){
		System.out.println("NO1:Demo14()" + this.hashCode());
	}
	public void init() throws ServletException {
		System.out.println("NO2:init()" + this.hashCode());
	}
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		System.out.println("NO3:doGet()" + this.hashCode());
		System.out.println("----------------");
	}
	public void destroy() {
		System.out.println("destroy()");
	}
}


2次请求结果
NO1:Demo14()2080023944
NO2:init()2080023944
NO3:doGet()2080023944
----------------
NO3:doGet()2080023944

 

 

web.xml细节

 <servlet>
    <servlet-name>Demo14</servlet-name>
    <servlet-class>cn.feihzou.web.servlet.Demo14</servlet-class>


    <!--配置参数-->
    <init-param>
    	<param-name>encoding</param-name>
    	<param-value>GBK</param-value>
    </init-param>


     <!-- 数字小的先加载,最小为0,如果为负数和没有设置一样,实例在浏览器第一次访问时创建  -->
    <load-on-startup>1</load-on-startup>
  </servlet>
    <servlet-mapping>
    <servlet-name>Demo14</servlet-name>


    <!--一个Servlet的url-pattern可以是1个或多个-->
    <url-pattern>/Demo14</url-pattern>
    <url-pattern>/Demo014</url-pattern>
   
  </servlet-mapping>

代码

 

public class Demo14 extends HttpServlet {
	 
	public Demo14(){
		System.out.println("NO1:Demo14()" + this.hashCode());
	}
	public void init(ServletConfig config) throws ServletException {
		System.out.println("NO2:init()" + this.hashCode());
		
	 
//		 String encoding = config.getInitParameter("encoding");//获取参数
	 
		Enumeration<String> enums = config.getInitParameterNames();
		while(enums.hasMoreElements()){
			String key = enums.nextElement();
			String value = config.getInitParameter(key);
			System.out.println("初始化参数配置:"+key+"-"+value);
		}
		 
	}
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		System.out.println("NO3:doGet()" + this.hashCode());
		System.out.println("----------------");
	 
	}
	public void destroy() {
		System.out.println("destroy()");
	}
}
请求http://localhost:8080/Demo014

响应的结果

NO1:Demo14()973447927
NO2:init()973447927
初始化参数配置:encoding-GBK
NO3:doGet()973447927
----------------

 

Servlet细节

1在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:

一种格式是“*.扩展名”,

一种格式是以正斜杠(/)开头并以“/*”结尾

2Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。

3针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。

4在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。

5对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法

6如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。 凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求

7在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。 当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。

8WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。

9ServletContext对象被包含在ServletConfig对象中,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得对ServletContext对象的引用。

10由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象

11ServletContext应用

  1. 多个Servlet通过ServletContext对象数据共享。
  2.  获取WEB应用的初始化参数。
  3. 实现Servlet的转发。
  4. 利用ServletContext对象读取资源文件。 

 

12Servlet与缓存

  1. 设置缓存的两种场景: 场景一:对于不经常变化的数据,在servlet中可以为其设置合理的缓存时间值,以避免浏览器频繁向服务器发送请求,提升服务器的性能。 场景二:如果要实现一种高级功能,即客户端请求动态web资源时,动态web资源发现发给客户端的数据更新了,就给客户端发送最新的数据,如果发现数据没有更新,则动态web资源就要客户端就去访问它自己缓存的数据。此种情况可以通过覆写动态web资源(即servlet)的getLastModify方法予以实现。
  2. getLastModified方法由service方法调用,默认情况下,getLastModified方法返回一个负数,开发人员在编写servlet时,如果不覆盖getLastModified方法,则每次访问servlet时,service方法发现getLastModified方法返回负数,它就会调用doXXX方法向客户端返回最新的数据。此种情况下,服务器在向客户端返回doXXX方法返回的数据时,不会在数据上加Last-Modified头字段。
  3. 如果编写servlet时,覆盖了getLastModified方法,并返回某一个时间值,则客户端访问Servlet时,service方法首先会检查客户端是否通过If-Modified-Since头字段带一个时间值过来。如果没有的话,则service方法会调用doXXX方法向客户端返回最新的数据。在返回数据时,service方法还会调用getLastModified方法得到一个时间值,并以这个时间值在数据上加上一个Last-Modified头字段。(即通知客户端缓存数据)
  4. 客户端在访问servlet时,如果通过If-Modified-Since头字段带了一个时间值过来,则service方法在调用doXXX方法之前,它会先调用getLastModified方法,得到一个时间值,并与客户端带过来的时间值进行比较,如果比客户端的时间值要新,则service方法调用doXXX方法向客户端返回最新的数据。如果要旧,则service方法而不会调用doXXX方法向客户端返回数据,而是返回一个304的状态码给客户端,通知客户端在拿它缓存中的数据。