您的位置:首页 > 理论基础 > 计算机网络

精研Servlet,HttpServlet的实现追究

2013-12-10 14:46 417 查看


Servlet的优点:

servlet可以很好地替代公共网关接口(CommonGatewayInterface,CGI)脚本。通常CGI脚本是用Perl或者C语言编写的,它们总是和特定的服务器平台紧密相关。而servlet是用Java编写的,所以它们一开始就是平台无关的。这样,Java编写一次就可以在任何平台运行(writeonce,run
anywhere)的承诺就同样可以在服务器上实现了。servlet还有一些CGI脚本所不具备的独特优点:

1、servlet是持久的。servlet只需Web服务器加载一次,而且可以在不同请求之间保持服务(例如一次数据库连接)。与之相反,CGI脚本是短暂的、瞬态的。每一次对CGI脚本的请求,都会使Web服务器加载并执行该脚本。一旦这个CGI脚本运行结束,它就会被从内存中清除,然后将结果返回到客户端。CGI脚本的每一次使用,都会造成程序初始化过程(例如连接数据库)的重复执行。
2、servlet是与平台无关的。如前所述,servlet是用Java编写的,它自然也继承了Java的平台无关性。
3、servlet是可扩展的。由于servlet是用Java编写的,它就具备了Java所能带来的所有优点。Java是健壮的、面向对象的编程语言,它很容易扩展以适应你的需求。servlet自然也具备了这些特征。
4、servlet是安全的。从外界调用一个servlet的惟一方法就是通过Web服务器。这提供了高水平的安全性保障,尤其是在你的Web服务器有防火墙保护的时候。
5、setvlet可以在多种多样的客户机上使用。由于servlet是用Java编写的,所以你可以很方便地在HTML中使用它们,就像你使用applet一样。

但值得注意的是Servlet并不局限于Web领域(或者说是HTTP协议相关).你可能要自己去扩展javax.servlet.GenericServlet.上面第三点就是这个意思.

比如说:扩展javax.servlet.GenericServlet实现一个Servlet,搞搞电子邮件的smtp(SimpleMailTransferProtocol即简单邮件传输协议)服务器,你就是基于SMTP协议扩展了GenericServlet,也许你会叫它SMTPServlet.我们用的HttpServlet不就这个命名规范嘛.

综上所述,Servlet可以在各种协议下良好的运行应用程序.

也许现在很多人不再写Servlet,但Servlet是心脏,Servlet放在刚出世的时候,还是非常NB的.到现在,各种成熟好用的东西很多了.但不能忘本.....再深点说为什么要这么设计,体现了什么?我还真是说不上来了,我觉得上面的几点也已经表明为什么了.就是Java对协议的一个设计.....

JSP的本质就是Servlet,或者说(是吧,开始说的是java,汗)JavaWeb开发的本质也就是Servlet+JDBC.任何性质的框架技术最底层的依然是基于他们2个.因此如果自己想写一套如SSH那样的框架技术,Java最底层的东西是必须掌握的.

Servlet被称为"服务器端小程序."是运行在服务器端的程序,用于处理以及响应客户端的请求.

HTTP目前支持7种请求方法:GET、POST、PUT、DELETE和TARCE,HEAD、OPTIONS.前四个都是客户端请求数据这类相关的方法.

GET请求获取由Request-URI所标识的资源。
POST在Request-URI所标识的资源后附加新的数据。
PUT请求服务器存储一个资源,并用Request-URI作为其标识。
DELETE请求服务器删除由Request-URI所标识的资源。

TRACE请求服务器回送收到的请求信息,主要用语测试或诊断。
HEAD请求获取由Request-URI所标识的资源的响应消息报头。
OPTIONS请求查询服务器的性能,或查询与资源相关的选项和需求。

我在这里只是列出HTTP的请求方法,具体的HTTP协议请参考这篇文章:http://my.oschina.net/zhaoqian/blog/90315

Servlet是个特殊的类,这个类必须继承HttpServlet.Servlet提供了相对于HTTP数据请求的四个方法的请求(其他三个也提供了,但我懒得写了,很少用到).

doGet:用于响应上面绿色字体的GET请求.
doPost:用于响应客户端的POST请求.
doPut:用于响应客户端的PUT请求.
doDelete:用于响应客户端的Delete请求.

事实上,HTTP这个大好青年被浪费了,大部分我们就是使用GET/POST请求,至于PUT/DELETE都不知道被遗弃到哪里去了.但最近几年兴起的一种REST模型的WEB服务,让HTTP协议发出了第二春.具体详见:http://my.oschina.net/zhaoqian/blog/90321

而诸如Struts2,SpringMVC这类的框架,也就是使用GET/POST,但工作时间久后,越发的感觉到,很多新技术,没必要去追,所需要的是,搞清楚追底层的,以不变的底层去应对万变的新技术.

Servlet的示例代码:

01
package
org.credo.test;
02
03
import
java.io.IOException;
04
05
import
javax.servlet.ServletConfig;
06
import
javax.servlet.ServletException;
07
import
javax.servlet.annotation.WebServlet;
08
import
javax.servlet.http.HttpServlet;
09
import
javax.servlet.http.HttpServletRequest;
10
import
javax.servlet.http.HttpServletResponse;
11
12
/**
13
*
<P>Project:Credo'sBase</P>
14
*
<P>Description:Servlet3.0的第一个测试.</P>
15
*
<P>Copyright(c)2012LionCredo.AllRightsReserved.</P>
16
*
@author<ahref="zhaoqianjava@qq.com">LionCredo</a>
17
*/
18
@WebServlet
(name=
"firstServlet"
,urlPatterns=
"/firstServlet"
)
19
public
class
ServletTest1
extends
HttpServlet{
20
21
private
static
final
long
serialVersionUID
=-2149324298582445679L;
22
23
@Override
24
public
void
init(ServletConfig
config)
throws
ServletException
{
25
//初始化Servlet的时候,可以在这里完成某些初始化的方法.
26
super
.init(config);
27
}
28
29
@Override
30
protected
void
service(HttpServletRequest
arg0,HttpServletResponsearg1)
throws
ServletException,
IOException{
31
//大部分时候,对于所有请求都是一样的话,可以重写HttpServlet的Service方法来替代doGet/doPost这些方法.
32
super
.service(arg0,
arg1);
33
}
34
35
@Override
36
public
void
destroy()
{
37
//
在销毁Servlet之前,需要完成某些资源的回收,比如关闭数据库链接等,可以写在这里.
38
super
.destroy();
39
}
40
}

HttpServlet

public
abstractclassjavax.servlet.http

Extends:GenericServlet

Implements:java.io.Serializable

提供将要被子类化以创建适用于Web站点的HTTPservlet的抽象类。HttpServlet的子类至少必须重写一个方法,该方法通常是以下这些方法之一:

•doGet,如果servlet支持HTTPGET请求

•doPost,用于HTTPPOST请求

•doPut,用于HTTPPUT请求

•doDelete,用于HTTPDELETE请求

•init和destroy,用于管理servlet的生命周期内保存的资源

•getServletInfo,servlet使用它提供有关其自身的信息

几乎没有理由重写service方法。service通过将标准HTTP请求分发给每个HTTP请求类型的处理程序方法(上面列出的doXXX方法)来处理它们。

同样,几乎没有理由重写doOptions和doTrace方法。

servlet通常运行在多线程服务器上,因此应该意识到servlet必须处理并发请求并小心地同步对共享资源的访问。共享资源包括内存数据(比如实例或类变量)和外部对象(比如文件、数据库连接和网络连接)。有关在Java程序中处理多个线程的更多信息,请参见JavaTutorialonMultithreadedProgramming。

上面是查阅官方的API所得的说明,实际上javaweb开发中,很少有web开发完全严格的使用Http协议.所以说大好青年浪费不是没道理的,但商业的实现手段就是商业的实现手段,技术永远是其次的.当然,REST这个嘛,第二春....再详细的方法就看HttpServlet的源码或者API.

另外,为什么不重写servlet的service方法有更详细的文章:http://my.oschina.net/dtkking/blog/89443

===========================================


一个Servlet继承抽象类HttpServlet,而HttpServlet继承GenericServlet,


abstractGenericServlet

Implements:Servlet,ServletConfig,java.io.Serializable

Extendedby:HttpServlet

定义一般的、与协议无关的servlet。要编写用于Web上的HTTPservlet,请改为扩展javax.servlet.http.HttpServlet。

GenericServlet实现Servlet和ServletConfig接口。servlet可以直接扩展GenericServlet,尽管扩展特定于协议的子类(比如HttpServlet)更为常见。

GenericServlet使编写servlet变得更容易。它提供生命周期方法init和destroy的简单版本,以及ServletConfig接口中的方法的简单版本。GenericServlet还实现log方法,在ServletContext接口中对此进行了声明。

要编写一般的servlet,只需重写抽象service方法即可。

剥离了一大堆注释的源码:

01
package
javax.servlet;
02
03
import
java.io.IOException;
04
import
java.util.Enumeration;
05
06
public
abstract
class
GenericServlet
implements
Servlet,
ServletConfig,
07
java.io.Serializable
{
08
09
private
static
final
long
serialVersionUID
=1L;
10
11
//java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。
12
//Java的serialization提供了一种持久化对象实例的机制。
13
//当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。
14
//为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。
15
//当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。
16
private
transient
ServletConfig
config;
17
18
public
GenericServlet()
{
19
//构造方法
20
}
21
22
@Override
23
public
void
destroy()
{
24
//销毁
25
}
26
27
@Override
28
public
String
getInitParameter(Stringname){
29
return
getServletConfig().getInitParameter(name);
30
}
31
32
@Override
33
public
Enumeration<String>
getInitParameterNames(){
34
return
getServletConfig().getInitParameterNames();
35
}
36
37
@Override
38
public
ServletConfig
getServletConfig(){
39
return
config;
40
}
41
42
*/
43
@Override
44
public
ServletContext
getServletContext(){
45
return
getServletConfig().getServletContext();
46
}
47
48
@Override
49
public
String
getServletInfo(){
50
return
""
;
51
}
52
53
@Override
54
public
void
init(ServletConfig
config)
throws
ServletException
{
55
this
.config
=config;
56
this
.init();
57
}
58
59
public
void
init()
throws
ServletException
{
60
//
NOOPbydefault
61
}
62
63
public
void
log(String
msg){
64
getServletContext().log(getServletName()
+
":
"
+
msg);
65
}
66
67
public
void
log(String
message,Throwablet){
68
getServletContext().log(getServletName()
+
":
"
+
message,t);
69
}
70
71
@Override
72
public
abstract
void
service(ServletRequest
req,ServletResponseres)
73
throws
ServletException,
IOException;
74
75
@Override
76
public
String
getServletName(){
77
return
config.getServletName();
78
}
79
}
可以看到,HttpServlet,是基于Http协议扩展了GenericServlet的抽象类.
而GenericServlet是实现了Servlet,ServletConfig,以及必须的Serializable序列化.下面主要看实现的2个接口,Servlet,ServletConfig都定义了那些接口.

===========================================================


publicinterfacejavax.servlet

Implementedby:FacesServlet,GenericServlet,JspPage

定义所有servlet都必须实现的方法。

servlet是运行在Web服务器中的小型Java程序。servlet通常通过HTTP(超文本传输协议)接收和响应来自
Web客户端的请求。

要实现此接口,可以编写一个扩展javax.servlet.GenericServlet的一般servlet,或者编写一个扩展
javax.servlet.http.HttpServlet的HTTPservlet。

此接口定义了初始化servlet的方法、为请求提供服务的方法和从服务器移除servlet的方法。这些方法称为生命周期方法,它们是按以下顺序调用的:

1.构造servlet,然后使用init方法将其初始化。

2.处理来自客户端的对service方法的所有调用。

3.从服务中取出servlet,然后使用destroy方法销毁它,最后进行垃圾回收并终止它。

除了生命周期方法之外,此接口还提供了
getServletConfig方法和getServletInfo方法,servlet可使用前一种方法获得任何启动信息,而后一种方法允许servlet返回有关其自身的基本信息,比如作者、版本和版权。

可以看源码,API,都可以发现servlet是一个接口.定义了五个方法.

01
package
javax.servlet;
02
03
import
java.io.IOException;
04
05
public
interface
Servlet
{
06
07
public
void
init(ServletConfig
config)
throws
ServletException;
08
09
public
ServletConfig
getServletConfig();
10
11
public
void
service(ServletRequest
req,ServletResponseres)
12
throws
ServletException,
IOException;
13
14
public
String
getServletInfo();
15
16
public
void
destroy();
17
}


publicinterfacejavax.servletServletConfig

Implementedby:GenericServlet

servlet容器使用的servlet配置对象,该对象在初始化期间将信息传递给servlet。

看上图Servlet接口中有getServletConfig.从这个接口的定义可以结合起来.

01
package
javax.servlet;
02
03
import
java.util.Enumeration;
04
05
public
interface
ServletConfig
{
06
07
public
String
getServletName();
08
09
public
ServletContext
getServletContext();
10
11
public
String
getInitParameter(Stringname);
12
13
public
Enumeration<String>
getInitParameterNames();
14
}
==========================================================================


可以看到,正常下我们使用的的ServletextendhttpServlet,


然后实质上的httpServletextends
GenericServlet,


而GenericServlet实现implements


1.接口Servlet,2.接口ServletConfig,以及
3.java.io.Serializable.

具体的接口定义和抽象类的实现,可以看看源代码,不过话说回来,我现在的目的也就是搞清楚,而非是自己写,那样精力消耗太大.毕竟源码是轻易获得的,想看明白就行了.

=====================================================================================================


HttpServletRequest,HttpServletResponse

下一个将粗略说下HttpServletRequest,HttpServletResponse.这两个写下就知道是什么情况了.

HttpServletRequest,HttpServletResponse,在Servlet里是什么意思,一目了然.

Web基于HTTP的开发中,这两货是天天用的东西.两者都是接口.


HttpServletRequest,HttpServletResponse对象简介:

客户端对于Servlet的每次访问请求,Servlet容器(如Tomcat)都会创建一个封装HTTP请求的对象和一个代表HTTP响应的对象,当调用Servlet的doGet或doPost方法时,这两个对象会作为参数被传递进去





HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,所发出的HTTP请求消息被封装在此对象之中,通过这个对象提供的方法,即可获得客户端发出的请求信息。

HttpServletRequest对象最基本的应用是获取浏览器传递给Web服务器的请求参数信息

请求参数:
▪GET方式下,URL地址后的附加信息
▪POST方式下,HTTP请求消息中的实体内容部分







具体的示例嘛...:日,不想写了,这些太简单了,随便去网上找的DEMO看啦.

读取请求参数的方法

通过HttpServletRequest对象的以下方法读取GET/POST方式下传递的参数

getParameter

getParameterValues


HttpServletResponse对象代表服务器端对客户端的响应,用于封装HTTP响应消息

输出响应正文(实体内容)输出响应正文的方法

▪getWriter

–返回一个(文本)字符输出流对象

–专用于输出内容为文本字符的网页文档

▪getOutPutStream

–返回一个字节输出流对象

–如果要输出二进制格式的响应正文,应该使用该方法




01
public
class
Servlet1
extends
HttpServlet
{
02
public
void
doGet(HttpServletRequest
request,HttpServletResponseresponse){
03
response.setContentType(
"text/html"
);
04
PrintWriter
out=response.getWriter();
05
String
userName=request.getParameter(
"userName"
);
06
//通过PrintWriter类型对象out的println方法,输出内容至浏览器
07
out.println(
"username:"
+userName+
"<br/>"
);
08
//显式清理缓存和关闭
09
out.flush();
10
out.close();
11
}
如上示例.

HttpServletResponse其它常用方法

}字符集编码问题

}重定向
具体百度下吧,不想写了,我遁了.......
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: