刚接触Servlet时感觉有点晕,各种与servlet相关的东西。从API上弄了点东西,供初学者参考。
Servlet是运行在服务器端的程序,Sun只是制定了其规范(即只定义了接口),而由Servlet容器来具体实现。所以,Servlet程序的具体实现因容器的不同而不同。但是都遵循同一个规范。
javax.servlet.Servlet是个Interface,其他的各种Servlet都必须继承或者实现这个接口。
Servlet这个接口被以下类、抽象类或者接口实现:FacesServlet(类), GenericServlet(抽象类), JspPage(接口)。
这三个里面我们讲一下GenericServlet(javax.servlet.GenericServlet):
以上可知,这个抽象类实现了Servlet, ServletConfig, java.io.Serializable。但这些都是空实现,而且没有实现service方法,由容器具体实现。HttpServlet(javax.servlet.http.HttpServlet)这个有具体实现的抽象类继承了GenericServlet,这是个基于http特定协议的servlet。举个Servlet类的例子:
可以看到,我们一般的基于http协议编程的Servlet类直接继承了HttpServlet。
在每个Servlet类中都有doGet和doPost方法,我们看看他们后面的参数,比如doPost:
其实,根据规范应该有这个通用方法来服务请求:
而HttpServlet是针对Http协议的实现,所以HttpServlet把这个方法重写为:
可以看到,最后实际上调用了:
而在这个方法内部,又根据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文件中进行配置,其格式如下:
我们通过浏览器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中如下配置:
<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对象,则可以如下方式获取:
2、ServletConfig中有getServletContext()这样一个方法,这也是ServletConfig主要的用处。但是如何获取ServletConfig对象呢?[color=red]注意:在前文中已经提到,我们一般的servlet继承了HttpServlet,而HttpServlet又继承了GenericServlet,GenericServlet实现了ServletConfig接口。[/color]因此可以这么获取ServletContext对象:
[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容器会自动使用线程池等技术来支持系统的运行。
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容器会自动使用线程池等技术来支持系统的运行。