关于Servlet基础的一点东西

本文介绍了Servlet的基本概念,包括Servlet的初始化、终止阶段及如何访问Servlet。同时探讨了Servlet的单例特性及其对并发请求的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚接触Servlet时感觉有点晕,各种与servlet相关的东西。从API上弄了点东西,供初学者参考。

Servlet是运行在服务器端的程序,Sun只是制定了其规范(即只定义了接口),而由Servlet容器来具体实现。所以,Servlet程序的具体实现因容器的不同而不同。但是都遵循同一个规范。

javax.servlet.Servlet是个Interface,其他的各种Servlet都必须继承或者实现这个接口。

Servlet这个接口被以下类、抽象类或者接口实现:FacesServlet(类), GenericServlet(抽象类), JspPage(接口)。

这三个里面我们讲一下GenericServlet(javax.servlet.GenericServlet):
public abstract class GenericServlet implements Servlet,ServletConfig,java.io.Serializable

以上可知,这个抽象类实现了Servlet, ServletConfig, java.io.Serializable。但这些都是空实现,而且没有实现service方法,由容器具体实现。HttpServlet(javax.servlet.http.HttpServlet)这个有具体实现的抽象类继承了GenericServlet,这是个基于http特定协议的servlet。举个Servlet类的例子:
public class LoginPage extends HttpServlet

可以看到,我们一般的基于http协议编程的Servlet类直接继承了HttpServlet。

在每个Servlet类中都有doGet和doPost方法,我们看看他们后面的参数,比如doPost:
public void doPost(HttpServletRequest request, HttpServletResponse response)


其实,根据规范应该有这个通用方法来服务请求:
public void service(ServletRequest req, ServletResponse res)

而HttpServlet是针对Http协议的实现,所以HttpServlet把这个方法重写为:
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {

HttpServletRequest request;
HttpServletResponse response;

try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}

可以看到,最后实际上调用了:
service(HttpServletRequest req, HttpServletResponse resp)

而在这个方法内部,又根据http协议的规定,分别对请求进行分析。如果是get请求,执行doGet方法;如果是post请求,执行doPost方法,等等等等。

我们看HttpServletRequest(HttpServletResponse类似)。这是个接口,它实现了ServletRequest接口,ServletRequest中有我们熟悉的setAttribute、getAttribute、getParameter、getParameterMap、getParameterValues、getRequestDispatcher等方法。

[color=darkblue]—————————————————————低调的分割线————————————————————[/color]

[color=darkblue][size=medium]Servlet初始化阶段:[/size][/color]
[list]
在下列时刻,Servlet容器装载Servlet:
[*]Servlet容器启动时自动装载某些Servlet
[*]在Servlet容器启动后,客户首次向Servlet发出请求
[*]Servlet的类文件被更新后,重新装载Servlet(.class文件)。访问时,同第二种情况
Servlet被装载后,Servlet容器创建一个Servlet实例并且调用Servlet的init()方法进行初始化。[color=red]在Servlet的整个生命周期中,init方法只被调用一次。[/color]
[/list]
[size=medium][color=darkblue]Servlet终止阶段[/color][/size]
[list]
在下列情况,Servlet容器终止Servlet:
[*]当Web应用被终止
[*]Servlet容器终止运行
[*]Servlet容器重新装载新实例
Servlet容器会先调用Servlet的destory方法。在destory方法中可以释放Servlet所占用的资源
[/list]

[color=darkblue]—————————————————————低调的分割线————————————————————[/color]

[color=darkblue][size=medium]访问Servlet:[/size][/color]

要访问Servlet,首先需要在web.xml文件中进行配置,其格式如下:
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>test.test</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>

我们通过浏览器http://localhost:8080/projectname/test来进行访问。可以看到,通过浏览器地址的/test对应到了<servlet-mapping>中的url-pattern,在根据其对应的servlet-name找到<servlet>中的servlet-class,这样就可以访问到相应的servlet了。

有的servlet配置并没有<servlet-mapping>,这样的servlet的作用并不是用来访问,而是用于servlet容器启动之后的初始化工作。在servlet类中重写init方法,并在web.xml中如下配置:
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>test.test</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>

<load-on-startup>内的数字无关紧要,只是标识这个servlet在容器启动后初始化的顺序。在容器启动后,会自动加载这个servlet,并执行其中的init方法。

[color=darkblue]—————————————————————低调的分割线————————————————————[/color]

[size=medium][color=darkblue]关于ServletContext:[/color][/size]

servlet容器启动一个应用时,会为此应用创建一个全局共享的ServletContext对象。此对象任何时候都可以访问,而且所有的servlet实例共享此对象。此外还有一个全局的ServletConfig对象,此对象包含了servlet的初始化信息。

[size=medium][color=darkblue]如何获得ServletContext对象?[/color][/size]

1、假设request为HttpServletRequest对象,则可以如下方式获取:
ServletContext context = request.getSession().getServletContext();


2、ServletConfig中有getServletContext()这样一个方法,这也是ServletConfig主要的用处。但是如何获取ServletConfig对象呢?[color=red]注意:在前文中已经提到,我们一般的servlet继承了HttpServlet,而HttpServlet又继承了GenericServlet,GenericServlet实现了ServletConfig接口。[/color]因此可以这么获取ServletContext对象:
ServletContext context = this.getServletContext();


[color=darkblue]—————————————————————低调的分割线————————————————————[/color]

[size=medium][color=darkblue]Servlet是单例的![/color][/size]

[color=red]Servlet是单例的,即多个请求由同一个Servlet对象进行处理。虽然只有一个对象进行处理,但对象会生成多个线程来处理多个请求。[/color]因此,在servlet中如果涉及写操作的话,最好不要使用成员变量,而使用局部变量。
三种避免多线程混乱的方法:
1、实现javax.servlet.SingleThreadModel(servlet2.4中已经废止)
2、使用局部变量(推荐,忘掉其他两种方法吧……)
3、使用synchronized块

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。Servlet容器会自动使用线程池等技术来支持系统的运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值