Servlet规范简介——web框架是如何注入到Servlet中的
Servlet规范简介——web框架是如何注入到Servlet中的
引言
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组
Servlet规范简介——web框架是如何注入到Servlet中的的更多相关文章
- Servlet规范简介
引言 Web 框架一般是通过一个 Servlet 提供统一的请求入口,将指定的资源映射到这个 servlet, 在这个 servlet 中进行框架的初始化配置,访问 Web 页面中的数据,进行逻辑处理 ...
- servlet的一个web容器中有且只有一个servlet实例或有多个实例的理解1
servlet的一个web容器中有且只有一个servlet实例或有多个实例的理解 (2013-06-19 19:30:40) 转载▼ servlet的非线程安全,action的线程安全 对提交 ...
- python 全栈开发,Day66(web应用,http协议简介,web框架)
一.web应用 web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件.应用程序有两种模式C/S.B/S.C/S是客户端 ...
- web应用,http协议简介,web框架
一.web应用 web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件.应用程序有两种模式C/S.B/S.C/S是客户端 ...
- 基于servlet实现一个web框架
servlet作为一个web规范.其本身就算做一个web开发框架,可是其web action (响应某个URI的实现)的实现都是基于类的,不是非常方便,而且3.0之前的版本号还必须通过web.xml配 ...
- 使用Eclipse工具开发Servlet(新建web项目->创建Servlet->部署和访问Servlet)
在Eclipse工具栏中的[File]->[New]->[Other],打开如下菜单栏,选择Dynamic Web Project 点击下一步,如下图所示: 这里Dynamic web m ...
- web框架的前生今世--从servlet到spring mvc到spring boot
背景 上世纪90年代,随着Internet和浏览器的飞速发展,基于浏览器的B/S模式随之火爆发展起来.最初,用户使用浏览器向WEB服务器发送的请求都是请求静态的资源,比如html.css等. 但是可 ...
- 从零写Java Web框架——实现Ioc依赖注入
大概思路 通过读取配置文件,获取框架要加载的包路径:base-package,类似于 Spring 配置文件中的: <context:component-scan base-package=&q ...
- Servlet 规范笔记—servlet概念及结构
Servlet, 这个词对java程序员并不陌生,我想几乎每个java程序员在学习J2EE知识时,首先学习的就是servlet,这是一种正确的学习方式,在我看来Servlet是J2EE的基础,要熟练 ...
随机推荐
- Git 分支管理和冲突解决
Git 分支管理和冲突解决 创建分支 git branch 没有参数,显示本地版本库中所有的本地分支名称. 当前检出分支的前面会有星号. git branch newname 在当前检出分支上新建分支 ...
- runtime
7.runtime实现的机制是什么,怎么用,一般用于干嘛. 你还能记得你所使用的相关的头文件或者某些方法的名称吗? 运行时机制,runtime库里面包含了跟类.成员变量.方法相关的API,比如获取类里 ...
- 虚函数的使用 以及虚函数与重载的关系, 空虚函数的作用,纯虚函数->抽象类,基类虚析构函数使释放对象更彻底
为了访问公有派生类的特定成员,可以通过讲基类指针显示转换为派生类指针. 也可以将基类的非静态成员函数定义为虚函数(在函数前加上virtual) #include<iostream> usi ...
- jquery load 和 iframe 比较
如果要加载的东西比较简单,里面的没有复杂的数据和逻辑,可以使用load.如果要加载的页面自身有复杂的逻辑.操作,还是建议使用ifame,因为iframe里面可以引入自身的js和样式,而load引入的东 ...
- Handler sendMessage 与 obtainMessage (sendToTarget)比较
转自:http://iaiai.iteye.com/blog/1992196 obtainmessage()是从消息池中拿来一个msg 不需要另开辟空间new new需要重新申请,效率低,obtian ...
- 转载自lanceyan: 一致性hash和solr千万级数据分布式搜索引擎中的应用
一致性hash和solr千万级数据分布式搜索引擎中的应用 互联网创业中大部分人都是草根创业,这个时候没有强劲的服务器,也没有钱去买很昂贵的海量数据库.在这样严峻的条件下,一批又一批的创业者从创业中获得 ...
- 微信小程序常见问题集合(长期更新)
最新更新: 新手跳坑系列:推荐阅读:<二十四>request:fail错误(含https解决方案)(真机预览问题 跳坑指南<七十>如何让微信小程序服务类目审核通过 跳坑六十九: ...
- python table转空格
有需求: 预留,先上代码: import os def Table_Space(file_name,lis_out,tab_num = 4): file_str = open(file_name,&q ...
- python pip方式安装selenium
pip --default-timeout=1000 install -U selenium
- 通过ip查询对方位置
我们这里使用的是baidumap的高精度IP定位API的接口,具体说明可以参考baidu提供的文档 使用前需要申请一个AK密钥类似于Kgcx......................xxl8w的样式 ...