引言

Web 框架一般是通过一个 Servlet 提供统一的请求入口,将指定的资源映射到这个 servlet, 在这个 servlet 中进行框架的初始化配置,访问 Web 页面中的数据,进行逻辑处理后,将结果数据与的表现层相融合并展现给用户。 WEB 框架想要在符合 Servlet 规范的容器中运行,同样也要符合 Servlet 规范。

将一个 WEB 框架注入到一个 servlet 中,主要涉及到 Servlet 规范中以下部分:

  • 部署描述符
  • 映射请求到 Servlet
  • Servlet 生存周期
  • 请求分发

Servlet 相关技术规范简介

部署描述符

部署描述符就是位于 WEB 应用程序的 /WEB-INF 目录下的 web.xml 的 XML 文件,是 WEB 应用程序不可分割的部分,管理着 WEB 应用程序的配置。部署描述符在应用程序开发人员,应用程序组装人员,应用程序部署人员之间传递 WEB 应用程序的元素和配置信息。

在 WEB 应用程序的部署描描述符中以下类型的配置和部署信息是所有的 servlet 容器必须支持的:

  • ServletContext 初始化参数
  • Session 配置
  • Servlet 声明
  • Servlet 映射
  • 应用程序生存周期监听器
  • Filter 的定义和映射
  • MIME 类型的映射
  • 欢迎文件列表
  • 错误文件列表

出现在部署描述符中的安全信息可以不被支持,除非这个 Servlet 容器是 J2EE 规范实现的一部分。

所有正确的 WEB 应用程序部署描述符 (Servlet2.3 规范 ) 必须包含下面的 DOCTYPE 声明:

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web

Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

下面说明在部署描述符中是如何进行 Servlet 声明和映射的,这个 DTD 的全部内容可以在下面这个地址获得:

http://java.sun.com/dtd/web-app_2_3.dtd

在这个 DTD 中有关 Servlet 声明和映射和映射的部分如下:

<!--

The servlet element contains the declarative data of a

servlet. If a jsp-file is specified and the load-on-startup element

is present, then the JSP should be precompiled and loaded.

Used in: web-app

-->

<!ELEMENT servlet (icon?, servlet-name, display-name?, description?,

(servlet-class|jsp-file), init-param*, load-on-startup?, runas?,

security-role-ref*)>

<!--

The servlet-class element contains the fully qualified class name

of the servlet.

Used in: servlet

-->

<!ELEMENT servlet-class (#PCDATA)>

<!--

The servlet-mapping element defines a mapping between a servlet

and a url pattern

Used in: web-app

-->

<!ELEMENT servlet-mapping (servlet-name, url-pattern)>

<!--

The servlet-name element contains the canonical name of the

servlet. Each servlet name is unique within the web application.

Used in: filter-mapping, servlet, servlet-mapping

-->

<!ELEMENT servlet-name (#PCDATA)>

根据以上 DTD ,一个典型的 Servlet 的声明的格式如下:

<servlet>

<servlet-name>catalog</servlet-name>

<servlet-class>com.mycorp.CatalogServlet</servlet-class>

<init-param>

<param-name>catalog</param-name>

<param-value>Spring</param-value>

</init-param>

</servlet>

一个典型的Servlet映射如下:

<servlet-mapping>

<servlet-name>catalog</servlet-name>

<url-pattern>/catalog/*</url-pattern>

</servlet-mapping>

通过上面的方法,我们就声明了一个名称为 catalog 的Servlet,它的实现类为com.mycorp.CatalogServlet,并且带有一个catalog参数,参数值为Spring,所有向/catalog/*的请求都被映射到名称为catalog的Servlet。

映射请求到 Servlet

接 收到一个请求后,WEB容器要确定转到哪一个WEB应用程序。被选择的应用程序的最长的上下文路径必须和请求的URL开始部分匹配。URL匹配的部分是映射到Servlet的上下文路径。

WEB 容器下一步必须按照下面的程序定位处理请求的Servlet。

用来映射到Servlet的路径是请求对象的URL减去上下文的路径。下面的URL路径映射规则按顺序执行,容器选择第一个成功的匹配并且不在进行下一个匹配:

  • 容器试着对请求的路径和Servlet的路径进行精确匹配,如果匹配成功则选择这个Servlet。
  • 容器会循环的去试着匹配最长的路径前缀:把’/’当作路径分隔符,按照路径树逐级递减的完成,选择最长匹配的Servlet。
  • 如果这个URL路径的最后有扩展名(比如.jsp),Servlet容器会试着匹配处理这个扩展名的Servlet。
  • 如果前面的没有与前面三条规则相匹配的Servlet,容器会试着为资源请求提供适当的资源,如果有“默认”的Servlet定义给这个应用程序,那么这个Servlet会被使用。

容器必须使用一个大小写敏感的匹配方式。

在部署描述符中,用下面的语法定义映射:

  • 一个以’/’开始并且以’/*’结束的字符串用来映射路径。
  • 一个以’*.’为前缀的字符串用来映射扩展名。
  • 一个只包含’/’的字符串指示着这个应用程序“默认”的Servlet,在这种情况下,servlet的路径是请求的URI减去上下文路径,并且这个路径是null。
  • 所有其他的字符只用来精确匹配。

如果容器内置JSP容器,那么*.jsp被映射到这个容器,并允许JSP页面在需要的时候被执行。这种映射叫做隐含映射。如果WEB应用程序中定义了*.jsp的映射,那么这个映射有比隐含映射高的优先级。

WEB 容器允许显式的声明隐含映射以获得优先级,例如,*.shtml的隐含映射可以在服务器上被映射为包含功能。

映射实例:

path pattern

servlet

/foo/bar/*

servlet1

/baz/*

servlet2

/catalog

servlet3

*.bop

servlet4

下面是实际请求映射的结果

incoming path

servlet handling request

/foo/bar/index.html

servlet1

/foo/bar/index.bop

servlet1

/baz

servlet2

/baz/index.html

servlet2

/catalog

servlet3

/catalog/index.html

“default” servlet

/catalog/racecar.bop

servlet4

/index.bop

servlet4

请注意/catalog/index.html 和/catalog/racecar.bop这两种情况,因为是精确匹配,所以并没有映射到处理/catalog的servlet。

Servlet 生存周期

在介绍 Servlet 的生存周期之前需要先介绍一下 javax.servlet.Servlet 接口。所有的 Servlet 必须实现或者间接实现这个借口,我们通常可以通过继承 javax.servlet.GenericServlet 或者 javax.servlet.http.HttpServlet. 类来实现这个接口。

这个接口中定义了下面 5 种方法:

public void init(ServletConfig config);

public ServletConfig getServletConfig();

public void service(ServletRequest req, ServletResponse res);

public String getServletInfo();

public void destroy() ;

init() 方法

init 方法在容器器装入 Servlet 时执行, Servlet 容器在实例化后只调用一次 init 方法, init 方法必须在 servlet 接收到任何请求之前完成。

这个方法通常用来进行一些资源的管理和初始化,如从配置文件读取配置数据,读取初始化参数,初始化缓冲迟等一次性的操作。

getServletConfig() 方法

GetServletConfig 方法返回一个 ServletConfig 对象,该对象用来返回这个 Servlet 的初始化信息和启动参数。返回的是传递到 init 方法 ServletConfig 。

Service() 方法

Service 方法是应用程序逻辑的进入点,是 servlet 方法的核心, WEB 容器调用这个方法来响应进入的请求,只有 servlet 成功被 init() 方法初始化后, Service 方法才会被调用。

getServletInfo() 方法

这个方法返回一个字符串对象,提供有关 servlet 的信息,如作者、版本等。

destroy() 方法

destroy 方法在容器移除 Servlet 时执行,同样只执行一次。这个方法会在所有的线程的 service() 方法执行完成或者超时后执行,调用这个方法后,容器不会再调用这个 servlet 的方法,也就是说容器不再把请求发送给这个 Servlet 。       这个方法给 servlet 释放占用的资源的机会,通常用来执行一些清理任务。

这个接口定义了初始化一个 servlet, 服务请求和从容器中移除 servlet 的方法。他们按照下面的顺序执行:

  1. servlet 被实例化后,用 init 方法进行初始化
  2. 客户端的任何请求都调用 service 方法
  3. servlet 被移除服务,调用 destroy 方法销毁

servlet 的生存周期如下图:

请求分发

请求分发可以让一个Servlet把请求分配到另外一个资源,RequestDispatcher接口提供了实现他的机制。可以通过下面两种方式从ServletContext中获得一个实现了RequestDispatcher接口的对象:

• getRequestDispatcher

• getNamedDispatcher

getRequestDispatcher方法接受一个指向目标资源的URL路径

RequestDispatcher rd = getServletContext().getRequestDispatcher(“/catalog”);

getNamedDispatcher方法接受一个Servlet名称参数,这个名称是在部署描述符中<servlet-name>元素指定的那个名称。

RequestDispatcher rd = getServletContext().getNamedDispatcher (“catalog”);

RequestDispatcher接口有两个方法,允许你在调用的servlet完成初步处理后把请求响应分配到另外一个资源,

forward()方法:

public void forward(ServletRequest request, ServletReponse reponse) throws SwerletException,IOException

forward方法上让你把请求转发到另外的Servlet或者jsp或者html等资源,由这个资源接下来负责响应。如:

RequestDispatcher rd = getServletContext().getRequestDispatcher(“/catalog”);

rd. forward(request,response);

include()方法:

public void include (ServletRequest request, ServletReponse reponse) throws SwerletException,IOException

include方法让你的Servlet响应中包含另外一个资源生成内容

RequestDispatcher rd = getServletContext().getRequestDispatcher(“/catalog”);

rd. include(request,response);

结合WebWork的具体分析

WebWork是由OpenSymphony组织开发实现MVC模式的J2EE Web框架。在介绍完servlet规范的相关内容后,我们看看WebWork是如何注入到一个Servlet中的,假设我们有一个上下文环境为“/WebWorkdDemo”的WEB应用。

部署描述符

在部署描述符中,我们需要进行如下配置:

<servlet>

<servlet-name>webwork</servlet-name>

<servlet-class>com.opensymphony.webwork.dispatcher.ServletDispatcher</servlet-class>

</servlet>

……

<servlet-mapping>

<servlet-name>webwork</servlet-name>

<url-pattern>*.action</url-pattern>

</servlet-mapping>

我们声明了一个名为webwork的Servlet和*.action到这个Servlet的映射,这个Servlet就是webwork中的controller,担任MVC框架中非常重要的控制器角色。

映射请求到Servlet

在XWork的配置文件xwork.xml中有如下片段:

<action name="demo" class=" webworkapp.DemoAction">

<result name="success" type="dispatcher">

<param name="location">/demo.jsp</param>

</result>

</action>

这样我们由http://localhost:8080/WebWorkDemo/demo.action这个URL向服务器发出请求时,WEB容器首先确定转到哪一个WEB应用程序,容器将请求URL和上下文环境进行匹配后知道将转到/WebWorkdDemo这个WEB应用。

接下来容器会在/WebWorkdDemo这个应用的部署描述符中进行查找处理这个请求的servlet,根据后缀*.action找到名称为webwork这个Servlet,这样根据部署描述符,这个请求被映射到webwork中的controller组件com.opensymphony.webwork.dispatcher.ServletDispatcher来处理。这个担任控制器组件的Servlet在他的service()方法中在根据请求的路径解析出对应的action来进行处理。

通过上面的的处理,实现了将web请求转到了webwork中的控制器ServletDispatcher。不止是webwork,实现MVC的web框架都需要进行类似的处理来将web请求转入到自己的controller.以便进行进一步的处理。

Servlet生存周期

ServletDispatcher这个Servlet的存周期可以如下:

1)      在服务器启动的时候,容器首先实例化ServletDispatcher

2)        实例化完成后,将调用init()方法,在init方法中执行了以下操作:

  • 初始化Velocity引擎
  • 检查是否支持配置文件重新载入功能。如果支持,每个request请求都将重新装载xwork.xml配置文件,在开发时非常方便。
  • 设置一些文件上传的信息,比如:上传临时目录,上传的最大字节等。

3)      每次请求都调用service()方法,在service方法中执行了以下方法

  • 通过request请求取得action的命名空间
  • 根据servlet请求的Path,解析出要调用该请求的Action的名字(actionName)
  • 创建Action上下文(extraContext),遍历HttpServletRequest、HttpSession、ServletContext 中的数据,并将其复制到Webwork的Map实现中,至此之后,所有数据操作均在此Map结构中进行,从而将内部结构与Servlet API相分离。
  • 以上述信息作为参数,调用ActionProxyFactory创建对应的ActionProxy实例。ActionProxyFactory 将根据Xwork 配置文件(xwork.xml)中的设定,创建ActionProxy实例,ActionProxy中包含了Action的配置信息(包括Action名称,对应实现类等等)。
  • 执行proxy的execute()方法

4)      容器移除Servlet 时执行destroy(),在ServletDispatcher这个Servlet中并没有重写destroy方法,在移除Servlet时,将什么也不做。

请求分发

WebWork提供了多种活灵活视图展现方式,例如还是我们上面在xwork.xml中的配置:

<action name="demo" class=" webworkapp.DemoAction">

<result name="success" type="dispatcher">

<param name="location">/demo.jsp</param>

</result>

</action>

根据以上配置当DemoAction的返回值为"success"时的处理类型为"dispatcher",当result的type为"dispatcher"时,通过javax.servlet.RequestDispatcher的forward()或include()方法将处理结果和表现层融合后展现给用户

我们可以看看WebWork提供的dispatcher类型Result Type的实现类com.opensymphony .webwork.dispatcher.ServletDispatcherResult中的代码片断:

HttpServletRequest request = ServletActionContext.getRequest();

HttpServletResponse response = ServletActionContext.getResponse();

RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);

if (dispatcher == null) {

response.sendError(404, "result '" + finalLocation + "' not found");

return;

}

if (!response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {

request.setAttribute("webwork.view_uri", finalLocation);

request.setAttribute("webwork.request_uri", request.getRequestURI());

dispatcher.forward(request, response);

} else {

dispatcher.include(request, response);

}

ServletDispatcherResult类的从ServletActionContex中得到HttpServletRequest和HttpServletResponse,然后调用request.getRequestDispatcher(finalLocation)方法得到一个RequestDispatcher实例,如果返回的是null,则输出404页面未找到的错误,否则将调用dispatcher.forward(request, response)或者dispatcher.include(request, response)进行请求分发,将处理结果和表现层融合后展现给用户。

Servlet规范简介的更多相关文章

  1. Servlet规范简介——web框架是如何注入到Servlet中的

    Servlet规范简介--web框架是如何注入到Servlet中的 引言 Web框架一般是通过一个Servlet提供统一的请求入口,将指定的资源映射到这个servlet,在这个servlet中进行框架 ...

  2. [原创]java WEB学习笔记47:Servlet 监听器简介, ServletContext(Application 对象), HttpSession (Session 对象), HttpServletRequest (request 对象) 监听器,利用listener理解 三个对象的生命周期

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  3. Java Servlet 技术简介

    Java Servlet 技术简介 Java 开发人员兼培训师 Roy Miller 将我们现有的 servlet 介绍资料修改成了这篇易于学习的实用教程.Roy 将介绍并解释 servlet 是什么 ...

  4. HTML5 视频规范简介

    HTML5 视频规范简介  创建于 2013-02-03, 周日 00:56  作者 白建鹏 HTML 一词是“超文本标记语言”(Hyper-Text Markup Language)的缩写,是用于描 ...

  5. servlet规范

    Servlet规范 一个最基本的 Java Web 项目所需的 jar 包只需要一个 servlet-api.jar ,这个 jar 包中的类大部分都是接口,还有一些工具类,共有 2 个包,分别是 j ...

  6. java web分享ppt大纲 -- servlet容器简介

    今天在公司分享了java web的ppt,把ppt大纲放在这里,希望可以帮助需要的人 servlet容器简介 定义 狭义上的,servlet容器为java Web应用提供运行时环境,负责管理servl ...

  7. Servlet规范总结

    Servlet接口 Servlet规范的核心接口即是Servlet接口,它是所有Servlet类必须实现的接口,在Java Servelt API中已经提供了两个抽象类方便开发者实现Servlet类, ...

  8. 从servlet规范说起

    servlet规范 1 servlet 3.1规范 1.1 What is servlet A servlet is a JavaTM technology-based Web component, ...

  9. 对Servlet规范的蜻蜓点水

    现在我们大家基本都用struts或springmvc进行java web的开发,但我们都知道java web的核心技术是jsp servlet javabean的组合.因此很有必要知道servlet规 ...

随机推荐

  1. NOI2018 D1T1 [NOI2018]归程 解题报告

    P4768 [NOI2018]归程 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点.\(m\) 条边的无向连通图(节点的编号从 \ ...

  2. HDU 2639 01背包求第k大

    Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  3. 解析json方式之net.sf.json

    前面转载了json解析的技术:fastjson,今天说下另外一种技术. 下载地址 本次使用版本:http://sourceforge.net/projects/json-lib/files/json- ...

  4. Spring学习--HelloWorld

    Spring: Spring 是一个开源框架. Spring 是为简化企业级应用开发而生,使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能. Spring 是一 ...

  5. 最大流算法 ISAP 模板 和 Dinic模板

    ISAP // UVa11248 Frequency Hopping:使用ISAP算法,加优化 // Rujia Liu struct Edge { int from, to, cap, flow; ...

  6. 【BZOJ4766】文艺计算姬 [暴力]

    文艺计算姬 Time Limit: 1 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description "奋战三星期,造台计算机 ...

  7. setInterval的使用和停用

    var res = self.setInterval(function(){ if(typeof(UE.getEditor('editor').body.innerHTML) != "und ...

  8. [Shell] shell 脚本循环恢复的问题

    在一个shell脚本中,我大概执行了如下一个脚本: ...} do ...} do ...} do done done done 假设上面的sleep 10秒就是代表我的程序需要执行10秒之久.而现在 ...

  9. libyuv编译【转】

    转自:http://blog.csdn.net/kl222/article/details/41309541 版权声明:本文为博主原创文章,未经博主允许不得转载. 下载代码(要FQ): git clo ...

  10. APMserv常见问题

    一.启动是提示apache启动失败,mysql启动成功 1.去掉ssl的勾选(勾选需要证书),重启看解决没有 2.端口被占,吧apache端口改成80或者8080端口(其他端口也可以试试,80的话访问 ...