Servlet 如何工作?Servlet 中的 Listener、Filter

        当用户从浏览器向服务器发起一个请求,通常会包含如下信息:http://hostname: port /contextpath/servletpath,hostname 和 port 是用来与服务器建立 TCP 连接,而后面的 URL 才是用来选择服务器中那个子容器服务用户的请求那服务器是如何根据这个 URL 来达到正确的 Servlet 容器中的呢?

     Tomcat7.0 中这件事很容易解决,因为这种映射工作有专门一个类来完成的,这个就是 org.apache.tomcat.util.http.mapper,这个类保存了 Tomcat 的 Container 容器中的所有子容器的信息,当 org.apache.catalina.connector. Request 类在进入 Container 容器之前,mapper 将会根据这次请求的 hostnane 和 contextpath 将 host 和 context 容器设置到 Request 的 mappingData 属性中。所以当 Request 进入 Container 容器之前,它要访问那个子容器这时就已经确定了。

                 

   MapperListener 的 init 方法代码 :

public void init() { 
       findDefaultHost(); 
       Engine engine = (Engine) connector.getService().getContainer(); 
       engine.addContainerListener(this); 
       Container[] conHosts = engine.findChildren(); 
       for (Container conHost : conHosts) { 
           Host host = (Host) conHost; 
           if (!LifecycleState.NEW.equals(host.getState())) { 
               host.addLifecycleListener(this); 
               registerHost(host); 
           } 
       } 
}

    这段代码的作用就是将 MapperListener 类作为一个监听者加到整个 Container 容器中的每个子容器中,这样只要任何一个容器发生变化,MapperListener 都将会被通知,相应的保存容器关系的 MapperListener 的 mapper 属性也会修改。for 循环中就是将 host 及下面的子容器注册到 mapper 中。

下图描述了一次 Request 请求是如何达到最终的 Wrapper 容器的,

               

 

请求到达最终的 Servlet 还要完成一些步骤,必须要执行 Filter 链,以及要通知你在 web.xml 中定义的 listener。

接下去就要执行 Servlet 的 service 方法了,通常情况下,我们自己定义的 servlet 并不是直接去实现 javax.servlet.servlet 接口,而是去继承更简单的 HttpServlet 类或者 GenericServlet 类,我们可以有选择的覆盖相应方法去实现我们要完成的工作。

Servlet 的确已经能够帮我们完成所有的工作了,但是现在的 web 应用很少有直接将交互全部页面都用 servlet 来实现,而是采用更加高效的 MVC 框架来实现。这些 MVC 框架基本的原理都是将所有的请求都映射到一个 Servlet,然后去实现 service 方法,这个方法也就是 MVC 框架的入口。 

Servlet 中的 Listener

       整个 Tomcat 服务器中 Listener 使用的非常广泛,它是基于观察者模式设计的,Listener 的设计对开发 Servlet 应用程序提供了一种快捷的手段,能够方便的从另一个纵向维度控制程序和数据。目前 Servlet 中提供了 5 种两类事件的观察者接口,它们分别是:4 个 EventListeners 类型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 个 LifecycleListeners 类型的,ServletContextListener、HttpSessionListener。

      这些 Listener 的实现类可以配置在 web.xml 中的 <listener> 标签中。当然也可以在应用程序中动态添加 Listener,需要注意的是 ServletContextListener 在容器启动之后就不能再添加新的,因为它所监听的事件已经不会再出现。掌握这些 Listener 的使用,能够让我们的程序设计的更加灵活。

ServletContextListener类中有一个接口:contextInitialized(ServletContextEvent sce)

      Context容器初始化时触发,在所有的Filter和Servlet的init方法调用之前调用这个接口。例如Spring的ContextLoaderListener实现了ServletContextListener,在容器加载时启动Spring容器,ContextLoaderListener在contextInitialized方法中初始化容器。

Servlet 中的Filter

       在web.xml中的另一个常用配置,通过<filter>和<filter-mapping>组合来使用Filter。实际上Filter可以完成与Servlet同样的工作,他也提供了request和response对象,还提供了一个FiltChain对象。

Filter生命周期

  • init(FilterConfig filterConfig) :Filter的创建与销毁由WEB服务器负责,web应用程序启动时,web服务器将创建Filter的实例对象,并调用init方法进行初始化(注意:filter对象只会创建一次,init方法也只会执行一次
  • doFilter(ServletRequest request, ServletResponse response, FilterChain chain) //这个是 Filter的核心方法被拦截请求在这里被处理
  • destroy() // Filter 实例销毁前的准备工作 

通常我们将自定义的Filter配置在web容器的web.xml中, 大致分为两个部分来配置这个Filter.

//声明filter
<filter>
    <filter-name>filter-name</filter-name>
    <filter-class>com.xx.FilterClass</filter-class>
//初始化参数
    <init-param>
        <param-name>key</param-name>
        <param-value>value</param-value>
    </init-param>
</filter>

//filter 拦截规则
<filter-mapping>
  <filter-mapping>
  <filter-name>filter-name</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Filter链——FilterChain

     在一个Web应用中,可以编写多个Filter,这些Filter组合起来称之为一个Filter链。
     web服务器根据Filter在web.xml文件中的注册顺序<filter-mapping>,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建第一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有则调用第二个filter,如果没有则调用目标资源。

FilterConfig接口

     用户在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的FilterConfig对象传递进来,因此开发人员在编写Filter时,通过FilterConfig对象的方法就可获得过滤器的初始化参数有关的信息以及获取ServletContext对象等信息。

加载顺序:

在web容器中, 最先加载的是 Listener, 其次是 Filter 最后是 Servlet。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值