Servlet开发流程及生命周期

我们可以通过三种方式来开发servlet:

A:实现Servlet接口

B:继承GenericServlet类

C:继承HttpServlet类

 

首先我们来说第一种方式:

实现Servlet接口

详细步骤:

1.在Tomcat目录下的webapps下面,新建自命名一个文件夹 myServlet。然后在该目录下新建WEB-INF文件夹,该文件夹下面再建classes、lib文件夹,还有web.xml文件。

servlet-1

在classes下面新建Hello.java文件

2.首先对环境进行配置,将Servlet-api.jar(此包默认包含在Tomcat安装目录的common\lib文件夹下)包加入classpath环境变量

接着完成Hello.java的代码编写,并编译。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.lpq;

import javax.servlet.*;
import java.io.*;

public class Hello implements Servlet{
    public void init(ServletConfig config) throws ServletException{
        System.out.println("init it");
    }

    public ServletConfig getServletConfig(){
        return null;
    }

    public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException{
        System.out.println("service it");
        PrintWriter pw = resp.getWriter();
        pw.print("Hello,World!");
    }

    public String getServletInfo(){
        return "";
    }

    public void destroy(){
        System.out.println("destroy");
    }
}

3.在web.xml文件中部署你的servlet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<servlet>
      <!--servlet-name 给该Servlet取名, 该名字可以自己定义:默认就使用该Servlet的名字-->

      <servlet-name>Hello</servlet-name>

      <!--servlet-class要指明该Servlet 放在哪个包下的,形式是包/包/../类-->

      <servlet-class>com.lpq.Hello</servlet-class>注意:后面不要带.java

</servlet>

              <!--Servlet的映射-->

<servlet-mapping>

              <!--这个Servlet-name要和上面的servlet-name名字一样-->

        <servlet-name>Hello</servlet-name>

              <!--url-pattern这里就是将来访问该Servlet的资源名部分-->

        <url-pattern>/hello</url-pattern>
</servlet-mapping>

4.启动tomcat访问servlet,在浏览器地址栏输入http://localhost:8080/myServlet/hello

即可看到浏览器显示的Hello,World!

我们可以发现,当我们刷新页面的时候,控制台只输出一次init it,而会每次访问都会输入service it。

 servlet-2

这里我们来说说Servlet的生命周期:

Servlet部署在容器里,这里我们使用的是tomcat,也可以是其它的容器如:weblogic    它的生命周期由容器来管理。

Servlet的生命周期分为以下几个阶段:

1、加载阶段

当Web服务器启动时,Servlet容器加载一个Java Servlet类,这个过程也有可能推迟到Web客户请求Servlet服务时发生。通常情况下,Servlet容器使用Java类加载器加载一个Servlet,可以加载本地的Servlet,也可以加载远程的Servlet。注意,Servlet只需要被加载一次,然后将会实例化该类的一个实例或者多个实例。

2.创建一个servlet实例。

Servlet容器调用Servlet的初始化方法HttpServlet.init()进行Servlet初始化。因此,我们可以通过重写init()方法进行初始化某些工作。

例如:通过重写init()方法,读取配置信息,完成数据连接等工作。

如果init()方法调用失败,则会发生ServletException,Servlet将不能正常工作。在这种情况下,该Serlvet将会被容器清除掉,清除该Servlet后,容器将重新初始化这个Servlet。

3.Servlet运行阶段

当Web服务器接受到浏览器的访问请求后,将把该请求传送给Servlet容器。Servlet容器将请求包装成HttpServletRequest和HttpServletResponse对象,封装从Web客户接收到的HTTP请求和由Servlet生成的响应。并使用这两个对象作为参数,调用service()方法。

在service()方法中,可以从HttpServletRequest类中提取来自HttpSession、reqeust或cookie等对象的状态信息,进行特定应用的处理,并且用HttpServletResponse对象生成HTTP响应数据。

4.Servlet结束时期

Servlet将一直运行到被服务器卸载,或者当Web服务器和容器关闭时。这种情况下将回收init()方法中使用的资源,如关闭数据库连接等。这些都是通过调用destrory()方法来实现的。
容器在调用destroy()方法前,它必须等待那些正在service()方法中执行的线程执行完毕或者在服务器定义的一段时间内执行(这个时间段在容器调用destroy()方法之前)。一旦destroy()方法被调用,容器就不会再向该实例发送任何请求。如果容器需要再使用该Servlet,它必须创建新的实例。destroy()方法完成后,容器必须释放Servlet实例以便它能够被垃圾回收。

A:tomcat重启     B:reload该webapps空间           C:重启电脑

继承GeneriServlet

通过继承GenericServlet去开发servlet,只需要重写service方法,相对来说简单一点。

1.同样新建一个HelloGen文件,继承GenericServlet,重写service方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.lpq;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class HelloGen extends GenericServlet{
    @Override
    public void service(ServletRequest req, ServletResponse resp)
    throws ServletException, IOException {
        // TODO Auto-generated method stub
        PrintWriter pw = resp.getWriter();
        pw.print("Hello,wrold!Generic");
    }
}

2.在web.xml文件中部署该servlet

1
2
3
4
5
6
7
8
9
<servlet>
      <servlet-name>HelloGen</servlet-name>
      <servlet-class>com.lpq.HelloGen</servlet-class>注意:后面不要带.java④

</servlet>
<servlet-mapping>
        <servlet-name>HelloGen</servlet-name>
        <url-pattern>/hellogen</url-pattern>
</servlet-mapping>

3.启动tomcat,输入http://localhost:8080/myServlet/hellogen    即可显示Hello,World!Generic

继承HttpServlet

通过继承HttpServlet去开发Servlet,需要重写doGet()   doPost()方法。这是目前使用的最多的一种方法。

我们先来说说get和post提交的区别:

1.从安全性来看post的安全性要高于get,get提交的数据会在浏览器地址栏显示。

2.从提交的内容大小来看,get提交的数据不能大于2K,而post提交的数据理论上不受限制,但是实际编程中不要大于64K

3.从请求响应速度来看,get的响应速度要快,get要求服务器立即处理请求,而post骑牛可能形成一个队列请求。

1.我们仍然写一个HelloHttp.java文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.lpq;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloHttp extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
        // TODO Auto-generated method stub
        PrintWriter pw = resp.getWriter();
        pw.print("Hello,wrold!HttpServlet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
        // TODO Auto-generated method stub
        this.doGet(req, resp);
    }
}

2.在web.xml文件中部署该servlet

1
2
3
4
5
6
7
8
9
<servlet>
      <servlet-name>HelloHttp</servlet-name>
      <servlet-class>com.lpq.HelloHttp</servlet-class>注意:后面不要带.java④

</servlet>
<servlet-mapping>
        <servlet-name>HelloHttp</servlet-name>
        <url-pattern>/hellohttp</url-pattern>
</servlet-mapping>

3.启动tomcat,输入http://localhost:8080/myServlet/hellohttp    即可显示Hello,World!HttpServlet

 

Servlet细节问题:

①    一个已经注册的Servlet可以被多次映射。

②    当映射一个servlet时候,可以多层 比如

<url-pattern>/servlet/index.html</url-pattern> ok

从这里还可以看出,后缀名是 html 不一定就是 html,可能是假象.

③    使用通配符在servlet映射到URL中

有两种格式:

第一种格式 *.扩展名 比如 *.do  *.ss

第二种格式 以 / 开头 同时以 /* 结尾  比如  /*  /news/*

通配符练习题:

l      Servlet1映射到 /abc/*

l      Servlet2映射到 /*

l      Servlet3映射到 /abc

l      Servlet4映射到 *.do

问题(面试题):

l      当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应

Servlet引擎将调用Servlet1。

l      当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应

Servlet引擎将调用Servlet3。

l      当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应

Servlet引擎将调用Servlet1

l      当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应

Servlet引擎将调用Servlet2。

l      当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应

Servlet引擎将调用Servlet2。

 

在匹配的时候,要参考的标准:

(1)    看谁的匹配度高,谁就被选择

(2)    *.do 的优先级最低

④    Servlet单例问题

 

当Servlet被第一次访问后,就被加载到内存,以后该实例对各个请求服务.即在使用中是单例.

因为 Servlet是单例,因此会出现线程安全问题: 比如:

售票系统. 如果不加同步机制,则会出现问题:

 

这里我给大家一个原则:

(1)       如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制

synchronized(对象){

//同步代码

}

(2)如果一个变量不需要共享,则直接在 doGet() 或者 doPost()定义.这样不会存在线程安全问题

 

⑤    servlet中的 <load-on-startup> 配置

需求: 当我们的网站启动的时候,可能会要求初始化一些数据,(比如创建临时表), 在比如:

我们的网站有一些要求定时完成的任务[ 定时写日志,定时备份数据.. 定时发送邮件..]

解决方法: 可以通过<load-on-startup> 配合 线程知识搞定.

 

先说明<load-on-startup>: 通过配置<load-on-startup> 我们可以指定某个Servlet 自动创建.

 

 

除非注明,饮水思源博客文章均为原创,转载请以链接形式标明本文地址

本文地址:http://www.alonemonkey.com/servlet-step.html

本文链接:http://www.alonemonkey.com/servlet-step.html