Fork me on GitHub

Servlet工作原理

  Servlet容器,形象地说就是担当Web服务器和Servlet之间的中间人的角色。Web服务器将被请求的Servlet的URI和request对象转交给Servlet容器,然后由Servlet容器调用相应的Servlet程序处理该请求,并将Servlet的请求结果返回给web服务器。

  Servlet容器与Servlet的交互主要是通过request和response对象来完成的,Servlet容器负责创建这些对象并传递给Servlet程序,Servlet程序则使用这些对象,并调用它们的方法来与Servlet容器进行通信。Servlet程序要使用这些对象,必须知道这些对象提供的方法约定,按照面向对象的松耦合模块化设计思想,只要让创建这些对象的类实现某一接口。Servlet API的主要作用就是定义了这些接口类。

  Servlet API中并没有定义用于创建request和response对象的具体类,它里面只定义了创建这些对象的类所需要实现的接口,它们具体的实现类则由各个Web容器厂商去实现。不管每个Web容器厂商设计的用于创建request和response对象的类叫什么名称,Servlet程序并不需要知道它们的具体名称,而是把它们都当做HttpServletRequest和HttpServletResponse这两个名称来对待。这样,Servlet程序就可以采用完全一样的方式来与各个厂商实现的Web容器进行交互,一个Servlet程序可以放置在任何一个厂家实现的Web容器中进行。注意:虽然Servlet源程序中引用的是Servlet API,但Servlet运行时真正调用的对象是由Servlet容器中的实现类创建的,因此,将Servlet API的Jar包增加到CLASSPATH环境变量中,只能保证Servlet程序可以被成功编译,但不能让Servlet程序离开Servlet容器运行。

  javax.servlet.Servlet是Servlet程序的一个重要接口,所有的Servlet必须实现这个接口或者继承该接口的实现类(例如HttpServlet)。Servlet接口定义了5个方法,集体定义如下:

为了更详细地了解Servlet容器的工作流程,下面先介绍一下Servlet的生命周期,Servlet的生命周期主要有以下几个过程。

1. 加载和实例化

  容器负责加载和实例化一个Servlet。实例化和加载可以发生在引擎启动的时候,也可以推迟到容器需要该Servlet为客户请求服务的时候。

2.  初始化

  init()方法用于 初始化操作,该方法在Servlet的整个生命周期中只被调用一次;初始化的过程主要是读取永久的配置信息,以及其他仅仅需要执行一次的任务。

3. 处理请求

  service()方法由Servlet容器调用,以允许Servlet响应一个请求。Servlet容器传递javax.servlet.ServletRequest对象和javax.servlet.ServletResponse对象。ServletRequest对象包含客户端HTTP请求信息,ServletrResponse则封装Servlet响应。

4. 移除实例

  调用destroy()方法(在整个生命周期中只被调用一次);服务器决定删除已经加载的Servlet实例之前将 调用Servlet的destroy()方法。

  当Servlet容器接收到一个请求后,首先到容器池内查找被请求的Servlet实例是否已经存在,若不存在,则会加载和实例化被请求的Servlet,并对它进行初始化;若已存在,则直接调用Servlet的service()方法,然后根据HTTP请求种类的不同,在service()内部调用doGet()或doPost()等方法处理相应的请求。当Servlet容器下一次接收到对该Servlet的请求时,则只需要重新创建一个ServletRequest对象和一个ServletResponse对象,并将它们作为参数传递给service()方法,同时新建一个线程处理该请求。最后当不需要该Servlet时,通过调用destroy()方法移除该实例。

  Servlet是单实例多线程,当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。这个线程安全问题主要是由于成员变量使用不当而引起的。那么如何编写线程安全的Servlet呢?

(1)同步对共享数据点的操作

  使用synchronized关键字能保证一次只有一个线程可以访问被保护的区段,在Servlet中可以通过同步块操作来保证线程的安全。

(2)避免使用成员变量(也称为实例变量)

   线程安全问题是由成员变量造成的,只要在Servlet中不使用成员变量,尽量使用局部变量,那么该Servlet就是线程安全的。

posted @ 2018-06-20 18:02  爱跑步的星仔  阅读(244)  评论(0编辑  收藏  举报