servlet工作机制

来源:互联网 发布:工商年报数据申请表 编辑:程序博客网 时间:2024/06/05 16:38

一、Web容器

在研究Servlet在tomcat中的工作机制前必须先看看Servlet规范的一些重要的相关规定,规范提供了一个Servlet接口,接口中包含的重要方法是init、service、destroy等方法,Servlet在初始化时要调用init方法,在销毁时要调用destroy方法,而对客户端请求处理时则调用service方法。对于这些机制的支持都必须由Tomcat内部去支持,具体则是由Wrapper容器提供支持。

在tomcat中消息流的流转机制是通过四个不同级别的容器管道机制进行流转的,对于每个请求都是一层一层处理的。如下图,当客户端请求到达服务端后请求被抽象成request对象后向四个容器进行传递,首先经过Engine容器的管道通过若干阀门,最后通过StandardEngineValve阀门流转到Host容器的管道,处理后继续往下流转,通过StandardHostValve阀门流转到Context容器的管道,继续往下流转,通过StandardContextValve阀门流转到Wrapper容器的管道,而对Servlet的核心处理也正是在StandardWrapperValve阀门中。StandardWrapperValve阀门调用Servlet的service方法队请求进行处理,然后对客户端响应。


当请求来到Http服务器,而Http服务器转交请求给容器时,容器会创建一个代表当次请求的HttpServletRequest对象,并将请求相关信息设置给该对象。同时,容器会创建一个HttpServletResponse对象(HttpServletRequest和HttpServletResponse都是接口,实现这些接口的相关类是由容器提供的),作为稍后对客户端进行响应的Java对象。接着,容器会根据读取的@WebServlet标注或者web.xml的设置,找出处理该请求的Servlet,调用它的service()方法,将创建的HttpServletRequest对象、HttpServletResponse对象传入作为参数,service()方法中会根据HTTP请求的方式,调用对应的doXXX()方法。接着在doGet方法中,可以使用HttpServletRequest对象、HtpServletResponse对象。使用getParameter()取得请求参数,使用getWriter()取得输出用的PrintWriter对象,并进行各项响应处理。对PrintWriter做的输出操作,最后由容器转换为HTTP响应,再由HTTP服务器对浏览器进行响应。之后容器将HttpServletRequest对象、HttpServletResponse对象销毁回收,该次请求响应结束。

二、Servlet生命周期

1、Servlet

在Servlet接口上,定义了与Servlet生命周期及请求服务相关的init()、service()、与destroy()三个方法。当Web容器启动后,会读取Servlet设置信息,将Servlet类加载并实例化,并未每个Servlet设置信息产生一个ServletConfig对象。而后调用Servlet接口的init()方法,并将产生的ServletConfig对象当作参数传入。

2、ServletConfig

ServletConfig即每个Servlet设置的代表对象,容器会为每个Servlet设置信息产生一个Servlet及ServletConfig实例。GenericServlet同时实现了Servlet及Servlet-Config接口,其主要目的是将初始Servlet调用init()方法传入的ServletConfig封装起来,GenericServlet在实现Servlet的init()方法时,也调用了另一个无参数的init()方法,在编写Servlet时,如果有一些初始时所要运行的动作,可以重新定义这个无参数的init()方法。

ServletConfig定义了getInitParameter()、getInitParameterNames()方法,可以取得设置Servlet时的初始参数

设置初始参数方法一:使用@WebServlet设置初始参数

[java] view plain copy
  1. @WebServlet(name="ServletConfigDemo",urlPatterns={"/conf"},  
  2.     initParams={  
  3.         @WebInitParam(name="PARAM1",value="VALUE1")  
  4.     })  
  5. public class ServletConfigDemo extends HttpServlet{  
  6.     private String PARAM1;  
  7.     public void init() throws ServletException{  
  8.         PARAM1 = getServletConfig().getInitParameter("PARAM1");  
  9.     }  
  10. }  

设置初始参数方法二:在web.xml中设置Servlet的初始参数,可以在<servlet>标签中使用<init-param>等标签进行设置,web.xml中的设置会覆盖标注的设置

3、ServletContext

ServletContext接口定义了运行Servlet的应用程序环境的一些行为和观点,可以使用ServletContext实现对象来取得锁清秋资源的URL、设置与储存 属性、应用程序初始参数,设置动态设置Servlet实例。当整个Web应用程序加载Web容器之后,容器会生成一个ServletContext对象作为整个应用程序的代表,并设置给ServletConfig,只要通过Servlet的getServletContext()方法就可以取得ServletContext对象。ServletContext的方法有:

(1)getRequestDispatcher():用来取得RequestDispatcher实例,使用时路径的指定必须以“/”作为开头,这个斜杠代表应用程序环境根目录(Context Root),取得RequestDispatcher实例之后,就可以进行请求的转发(forward)和包含(include)

(2)getResourcePaths():取得Web应用程序的某个目录中的文件

(3)getResourceAsStream():读取某个文件的内容

三、应用程序事件、监听器

1、ServletContext事件、监听器

(1)ServletContextListener是“生命周期监听器”,在Web应用程序初始化后或即将结束销毁前,会调用ServletContextListener实现类相对应的contextInitialized()或contextDestroyed()。可以在contextInitialized()中实现应用程序资源的准备动作,在contextDestroyed()实现释放应用程序资源的动作。

(2)ServletContextAttributeListener是“监听属性改变的监听器”,如果想要对象被设置、移除或替换ServletContext属性,可以收到通知以进行一些操作,则实现ServletContext AttributeListener中的方法attributeAdded()、attributeRemoved()、attributeReplaced()。

2、HttpSession事件、监听器

(1)HttpSessionListener是“生命周期监听器”,在HttpSession对象初始化或结束前,会分别调用sessionCreated()与sessionDestroyed()方法, 可以通过传入的HttpSessionEvent,使用getSession()取得HttpSession,以针对会话对象作出相对应的创建或结束处理操作。

(2)HttpSessionAttributeListener是“监听属性改变的监听器”,当在会话对象中加入属性,移除属性或者替换属性时,相对应的attributeAdded()、attributeRemoved()与attributeReplaced()方法就会被调用,并分别传入HttpSessionBindingEvent。

(3)HttpSessionBindingListener是“对象绑定监听器”,当加入HttpSession的属性对象,或从中移除时,就会调用valueBound()与valueUnbound()方法,并分别传入HttpSessionBindingEvent。

3、HttpServletRequest事件、监听器

(1)ServletRequesyListener是“生命周期监听器”,在ServletRequest对象初始化或结束前,会调用requestInitialized()与requestDestroyed()方法,通过传入的ServletRequestEvent来取得ServletRequest,以针对请求对象作出相对应的初始化或结束处理动作。

(2)ServletRequestAttributeListener是“属性改变监听器”,在请求对象中加入属性、移除属性或替换属性时,相对应的attributeAdded()、attributeRemoved()与attributeReplaced()方法会被调用,并分别传入ServletRequestAttributeEvent。

四、过滤器

在容器调用Servlet的service()方法前,Servlet并不会知道有请求的到来,而在Servlet的service()方法运行后,容器真正对浏览器进行HTTP响应之前,浏览器也不会知道Servlet真正的响应是什么。过滤器是介于Servlet之前,可拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。

1、实现与设置过滤器

在Servlet/JSP中要实现过滤器,必须实现Filter接口,并使用@WebFilter标注或在web.xml中定义过滤器,让容器知道该加载哪些过滤器。Filter接口有三个要实现的方法:init()、doFilter()与destroy()。

[java] view plain copy
  1. public interface Filter{  
  2.     public void init(FilterConfig filterConfig)throws ServletException;  
  3.     public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)throws IOException,ServletException;  
  4.     public void destroy();  
  5. }  

FilterConfig是实现Filter接口的类上使用标注或web.xml中过滤器设置信息的代表对象。如果在定义过滤器时设置了初始参数,则可以通过FilterConfig的getInitParameter()方法来去的初始参数。

当请求来到容器,而容器发现调用Servlet的service()方法前,可以应用某过滤器时,就会调用该过滤器的doFilter()方法。可以在doFilter()方法中进行service()方法的前置处理,而后决定是否调用FilterChain的doFilter()方法。如果调用了FilterChain的doFilter()方法,就会运行下一个过滤器,如果没有下一个过滤器了,就调用请求目标Servlet的service()方法。如果因为某个情况(如用户没有通过验证)而没有调用FilterChain的doFilter(),则请求就不会继续交给接下来的过滤器或者目标Servlet,这时就是所谓的拦截请求。在陆续调用完Filter实例的doFilter仍然到达Servlet的service()之后,流程就会以堆栈顺序返回,所以在FilterChain的doFilter()运行完毕后,就可以针对service()方法做后续处理。

在web.xml中设置过滤器如下,web.xml会覆盖掉标注的设置:

[html] view plain copy
  1. <filter>  
  2.     <filter-name>performance</filter-name>  
  3.     <filter-class>com.performance</filter-class>  
  4. </filter>  
  5. <filter-mapping>  
  6.     <filter-name>performance</filter-name>  
  7.     <url-pattern>/*</url-pattern>  
  8. </filter-mapping>  

<filter>标签中使用<filter-name>与<filter-class>设置过滤器名称与类名称。在<filter-mapping>中,则用<filter-name>与<url-pattern>来设置哪些URL请求必须应用哪个过滤器。

五、异步处理

Web容器会为每个请求分配一个线程,默认情况下,响应完成前,该线程占用的资源都不会被释放。若有些请求需要长时间处理,就会长时间占用线程所需资源,若这类请求很多,许多线程资源都被长时间占用,会对系统的性能造成负担。异步处理,可以先释放容器分配给请求的线程与相关资源,减轻系统负担,原先释放了容器所分配线程的请求,其响应将被延后,可以在处理完成时再对客户端进行响应。

ServletRequest上提供了startAsync()方法:

[java] view plain copy
  1. AsyncContext startAsync() throws IllegalStateException;  
  2. AsyncContext startAsync(ServletRequest servletRequest,ServletResponse servletResponse)throws IllegalStateException;  
这两个方法都会返回AsyncContext接口的实现对象,前者会直接利用原有的请求与响应对象来创建AsyncContext,后者可以传入自行创建的请求、响应封装对象。在调用了startAsync()方法取得AsyncContext对象之后,此次请求的响应会被延迟,并释放容器分配的线程。可以通过AsyncContext的getRequest()、getResponse()方法取得请求、响应对象,此次对客户端的响应将暂缓至调用AsyncContext的complete()或dispatch()方法为止,前者表示响应完成,后者表示将调派指定的URL进行响应。

注意:如要能调用ServletRequest的startAsync()以取得AsyncContext,必须告知容器此Servlet支持异步处理,如果使用@WebServlet来标注,则可以设置其asyncSupported为true。使用web.xml设置Servlet,则可以在<servlet>中设置<async-supported>标签为true。如果Servlet将会进行异步处理,其前端有过滤器,则过滤器亦需标示其支持异步处理,如果使用@WebFilter,同样可以设置其asyncSupported为true。

原创粉丝点击