Servlet容器工作原理.docx
- 文档编号:4448515
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:16
- 大小:23.07KB
Servlet容器工作原理.docx
《Servlet容器工作原理.docx》由会员分享,可在线阅读,更多相关《Servlet容器工作原理.docx(16页珍藏版)》请在冰豆网上搜索。
Servlet容器工作原理
Servlet容器工作原理
本文介绍一个简单servlet容器的基本原理。
现有两个servlet容器,第一个很简单,第二个则是根据第一个写出。
为了使第一个容器尽量简单,所以没有做得很完整。
复杂一些的servlet容器(包括TOMCAT4和5)在TOMCAT运行内幕的其他章节有介绍。
两个servlet容器都处理简单的servlet及staticResource。
您可以使用webroot/目录下的PrimitiveServlet来测试它。
复杂一些的servlet会超出这些容器的容量,您可以从TOMCAT运行内幕一书学习创建复杂的servlet容器。
两个应用程序的类都封装在ex02.pyrmont包下。
在理解应用程序如何运作之前,您必须熟悉javax.servlet.Servlet接口。
首先就来介绍这个接口。
随后,就介绍servlet容器服务servlet的具体内容。
javax.servlet.Servlet接口
servlet编程,需要引用以下两个类和接口:
javax.servlet和javax.servlet.http,在这些类和接口中,javax.servlet.Servlet接口尤为重要。
所有的servlet必须实现这个接口或继承已实现这个接口的类。
Servlet接口有五个方法,如下
publicvoidinit(ServletConfigconfig)throwsServletException
publicvoidservice(ServletRequestrequest,ServletResponseresponse)
throwsServletException,jspservletejb.io.IOException
publicvoiddestroy()
publicServletConfiggetServletConfig()
publicjspservletejb.lang.StringgetServletInfo()
init、service和destroy方法是Servlet生命周期的方法。
当Servlet类实例化后,容器加载init,以通知servlet它已进入服务行列。
init方法必须被加载,Servelt才能接收和请求。
如果要载入数据库驱动程序、初始化一些值等等,程序员可以重写这个方法。
在其他情况下,这个方法一般为空。
service方法由Servlet容器调用,以允许Servlet响应一个请求。
Servlet容器传递javax.servlet.ServletRequest对象和javax.servlet.ServletResponse对象。
ServletRequest对象包含客户端HTTP请求信息,ServletResponse则封装servlet响应。
这两个对象,您可以写一些需要servlet怎样服务和客户怎样请求的代码。
从service中删除Servlet实例之前,容器调用destroy方法。
在servlet容器关闭或servlet容器需要更多的内存时,就调用它。
这个方法只有在servlet的service方法内的所有线程都退出的时候,或在超时的时候才会被调用。
在servlet容器调用destroy方法之后,它将不再调用servlet的service方法。
destroy方法给了servlet机会,来清除所有候住的资源(比如:
内存,文件处理和线程),以确保在内存中所有的持续状态和servlet的当前状态是同步的。
Listing2.1包含了PrimitiveServlet的代码,此servlet非常简单,您可以用它来测试本文中的servlet容器应用程序。
PrimitiveServlet类实现了javax.servlet.Servlet并提供了五个servlet方法的接口。
它做的事情也很简单:
每次调用init,service或destroy方法的时候,servlet就向控制口写入方法名。
service方法也从ServletResponsec对象中获得java.io.PrintWriter对象,并发送字符串到浏览器。
Listing2.1.PrimitiveServlet.java
importjavax.servlet.*;
importjspservletejb.io.IOException;
importjspservletejb.io.PrintWriter;
publicclassPrimitiveServletimplementsServlet
{
publicvoidinit(ServletConfigconfig)throwsServletException
{
System.out.println("init");
}
publicvoidservice(ServletRequestrequest,ServletResponseresponse)
throwsServletException,IOException
{
System.out.println("fromservice");
PrintWriterout=response.getWriter();
out.println("Hello.Rosesarered.");
out.print("Violetsareblue.");
}
publicvoiddestroy()
{
System.out.println("destroy");
}
publicStringgetServletInfo()
{
returnnull;
}
publicServletConfiggetServletConfig()
{
returnnull;
}
}
Application1
现在,我们从servlet容器的角度来看看servlet编程。
一个功能健全的servlet容器对于每个servlet的HTTP请求会完成以下事情:
当servlet第一次被调用的时候,加载了servlet类并调用它的init方法(仅调用一次)
响应每次请求的时候,构建一个javax.servlet.ServletRequest和javax.servlet.ServletResponse实例。
激活servlet的service方法,传递ServletRequest和ServletResponse对象。
当servlet类关闭的时候,调用servlet的destroy方法,并卸载servlet类。
发生在servlet容器内部的事就复杂多了。
只是这个简单的servlet容器的功能不很健全,所以,这它只能运行非常简单的servelt,并不能调用servlet的init和destroy方法。
然而,它也执行了以下动作:
等待HTTP请求。
构建ServletRequest和ServletResponse对象
如果请求的是一个staticResource,就会激活StaticResourceProcessor实例的process方法,传递ServletRequest和ServletResponse对象。
如果请求的是一个servlet,载入该类,并激活它的service方法,传递ServletRequest和ServletResponse对象。
注意:
在这个servlet容器,每当servlet被请求的时候该类就被载入。
在第一个应用程序中,servlet容器由六个类组成。
HttpServer1
Request
Response
StaticResourceProcessor
ServletProcessor1
Constants
证如前文中的应用程序一样,这个程序的进入口(静态main方法)是HttpServer类。
这个方法创建了HttpServer实例,并调用它的await方法。
这个方法等待HTTP请示,然后创建一个request对象和response对象,根据请求是否是staticResource还是servlet来分派它们到StaticResourceProcessor实例或ServletProcessor实例。
Constants类包含staticfindWEB_ROOT,它是从其他类引用的。
WEB_ROOT指明PrimitiveServlet位置和容器服务的staticResource。
HttpServer1实例等待HTTP请求,直到它收到一个shutdown命令。
发布shutdown命令和前文是一样的。
HttpServer1类
此应用程序内的HttpServer1类与前文简单的WEB服务器应用程序中的HttpServer十分相似。
但是,此应用程序内的HttpServer1能服务静态资源和servlet。
如果要请求一个静态资源,请输入以下URL:
http:
//machineName:
port/staticResource
它就是前文中提到的怎样在WEB服务器应用程序里请求静态资源。
如果要请求一个servlet,请输入以下URL:
http:
//machineName:
port/servlet/servletClass
如果您想在本地浏览器请求一个PrimitiveServleservlet,请输入以下URL:
http:
//localhost:
8080/servlet/PrimitiveServlet
下面Listing2.2类的await方法,是等待一个HTTP请求,直到一个发布shutdown命令。
与前文的await方法相似。
Listing2.2.HttpServer1类的await方法
publicvoidawait(){
ServerSocketserverSocket=null;
intport=8080;
try{
serverSocket=newServerSocket(port,1,
InetAddress.getByName("127.0.0.1"));
}
catch(IOExceptione){
e.printStackTrace();
System.exit
(1);
}
//循环,等待一个请求
while(!
shutdown){
Socketsocket=null;
InputStreaminput=null;
OutputStreamoutput=null;
try{
socket=serverSocket.accept();
input=socket.getInputStream();
output=socket.getOutputStream();
//创建请求对象并解析
Requestrequest=newRequest(input);
request.parse();
//创建回应对象
Responseresponse=newResponse(output);
response.setRequest(request);
//检测是否是servlet或静态资源的请求
//servlet请求以"/servlet/"开始
if(request.getUri().startsWith("/servlet/")){
ServletProcessor1processor=newServletProcessor1();
processor.process(request,response);
}
else{
StaticResourceProcessorprocessor=
newStaticResourceProcessor();
processor.process(request,response);
}
//关闭socket
socket.close();
//检测是否前面的URI是一个shutdown命令
shutdown=request.getUri().equals(SHUTDOWN_COMMAND);
}
catch(Exceptione){
e.printStackTrace();
System.exit
(1);
}
}
}
此文await方法和前文的不同点就是,此文的await方法中的请求调度到StaticResourceProcessor或ervletProcessor。
如果URI中包含"/servlet/.",请求推进到后面,否则,请求传递到StaticResourceProcessor实例
Request类
Servletservice方法接受servlet容器的javax.servlet.ServletRequest和javax.servlet.ServletResponse实例。
因此,容器必须构建ServletRequest和ServletResponse对象,然后将其传递到正在被服务的service方法。
ex02.pyrmont.Request类代表一个请求对象传递到service方法。
同样地,它必须实现javax.servlet.ServletRequest接口。
这个类必须提供接口内所有方法的实现。
这里尽量简化它并只实现几个方法。
要编译Request类的话,必须提供这些方法的空实现。
再来看看request类,内部所有需要返回一个对象实例都返回null,如下:
publicObjectgetAttribute(Stringattribute){
returnnull;
}
publicEnumerationgetAttributeNames(){
returnnull;
}
publicStringgetRealPath(Stringpath){
returnnull;
}
另外,request类仍需有前文有介绍的parse和getUri方法。
Response类
response类实现javax.servlet.ServletResponse,同样,该类也必须提供接口内所有方法的实现。
类似于Request类,除getWriter方法外,其他方法的实现都为空。
publicPrintWritergetWriter(){
//autoflushistrue,println()willflush,
//butprint()willnot.
writer=newPrintWriter(output,true);
returnwriter;
}
PrintWriter类构建器的第二个参数是一个代表是否启用autoflush布尔值,如果为真,所有调用println方法都flush输出。
而print调用则不flush输出。
因此,如果在servelt的service方法的最后一行调用print方法,则从浏览器上看不到此输出。
这个不完整性在后面的应用程序内会有调整。
response类也包含有前文中介绍的sendStaticResource方法。
StaticResourceProcessor类
StaticResourceProcessor类用于服务静态资源的请求。
它唯一的方法是process。
Listing2.3.StaticResourceProcessor类的process方法。
publicvoidprocess(Requestrequest,Responseresponse){
try{
response.sendStaticResource();
}
catch(IOExceptione){
e.printStackTrace();
}
}
process方法接受两个参数:
Request和Response实例。
它仅仅是调用response类的sendStaticResource方法。
ServletProcessor1类
ServletProcessor1类用来处理对servlet的HTTP请求。
它非常简单,只包含了一个process方法。
而这个方法接受两个参数:
一个javax.servlet.ServletRequest实例和一个avax.servlet.ServletResponse实例。
process方法也构建了一个jspservletejb.net.URLClassLoader对象并使用它装载servlet类文件。
在从类装载器获得的Class对象上,process方法创建一个servlet实例并调用它的service方法。
process方法
Listing2.4.ServletProcessor1类中process方法
publicvoidprocess(Requestrequest,Responseresponse){
Stringuri=request.getUri();
StringservletName=uri.substring(uri.lastIndexOf("/")+1);
URLClassLoaderloader=null;
try{
//createaURLClassLoader
URLStreamHandlerstreamHandler=null;
URL[]urls=newURL[1];
FileclassPath=newFile(Constants.WEB_ROOT);
Stringrepository=(newURL("file",null,
classPath.getCanonicalPath()+File.separator)).toString()
urls[0]=newURL(null,repository,streamHandler);
loader=newURLClassLoader(urls);
}
catch(IOExceptione){
System.out.println(e.toString());
}
ClassmyClass=null;
try{
myClass=loader.loadClass(servletName);
}
catch(Exceptione){
System.out.println(e.toString());
}
Servletservlet=null;
try{
servlet=(Servlet)myClass.newInstance();
servlet.service((ServletRequest)request,(ServletResponse)response);
}
catch(Exceptione){
System.out.println(e.toString());
}
catch(Throwablee){
System.out.println(e.toString());
}
}
process方法接受两个参数:
一个ServletRequest实例和一个ServletResponse实例。
process方法通过调用getRequestUri方法从ServletRequest获取URI。
Stringuri=request.getUri();切记URI的格式:
/servlet/servletName
servletName是servlet类的名称。
如果要装载servlet类,则需要使用以下代码从URI获知servlet名称:
StringservletName=uri.substring(uri.lastIndexOf("/")+1);然后process方法装载servlet。
要做到这些,需要创建一个类装载器,并告诉装载器该类的位置,该servlet容器可以指引类装载器在Constants.WEB_ROOT指向的目录中查找。
在工作目录下,WEB_ROOT指向webroot/目录。
如果要装载一个servlet,则要使用jspservletejb.net.URLClassLoader类,它是java.lang.ClassLoader的间接子类。
一旦有了URLClassLoader类的实例,就可以使用loadClass方法来装载一个servlet类。
实例化URLClassLoader是很简单的。
该类有三个构建器,最简单的是:
publicURLClassLoader(URL[]urls);
urls是一组指向其位置jspservletejb.net.URL对象,当装载一个类时它会自动搜索其位置。
任一以/结尾的URL都被假定为一目录,否则,就假定其为.jar文件,在需要时可以下载并打开。
在一个servlet容器内,类装载器查找servlet类的位置称为储存库(repository)。
在所举的应用程序中,类装载器只可在当前工作目录下的webroot/目录查找,所以,首先得创建一组简单的URL。
URL类提供了多个构建器,因此有许多的方法来构建一个URL对象。
在这个应用程序内,使用了和TOMCAT内另外一个类所使用的相同的构建器。
该构建器头部(signature)如下:
publicURL(URLcontext,Stringspec,URLStreamHandlerhander)
throwsMalformedURLException
可以通过传递给第二个参数一个规范,传递给第一个和第三个参数null值来使用这个构建器,但在些有另外一种可接受三个参数的构建器:
publicURL(S
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Servlet 容器 工作 原理
![提示](https://static.bdocx.com/images/bang_tan.gif)