tomcat 8.0.36

知识点:

  • 动态监听器有七类:
  1. ServletContextAttributeListener
  2. ServletRequestListener
  3. ServletRequestAttributeListener
  4. HttpSessionIdListener
  5. HttpSessionAttributeListener
  6. HttpSessionListener
  7. ServletContextListener
  • 动态监听器必须在启动前完成,即使用ServletContainerInitializer或ServletContextListener进行动态添加。
  • 如果要动态添加ServletContextListener,只能使用ServletContainerInitializer进行。

ServletContext的addListener方法,是一个通过动态添加监听器的方法。

传入的参数必须是EventListener类型。

public <T extends EventListener> void addListener(T t)

添加的时机受到限制,必须在指定时机STARTING_PREP下才能添加。

if (!context.getState().equals(LifecycleState.STARTING_PREP)) {
throw new IllegalStateException(
    sm.getString("applicationContext.addListener.ise",
    getContextPath()));
}

STARTING_PREP的意思是启动前,tomcat在启动的时候有两个状态,一个是启动前,一个是正式启动,也就说在状态变为正式启动的时候,要把该添加的添加,不然就没机会了。

tomcat在维持启动前这个状态下,调用servlet api的方法主要有两个:

  1. ServletContainerInitializer#onStartup(Set<Class<?>> c, ServletContext ctx)
  2. ServletContextListener#contextInitialized(ServletContextEvent sce)

其实这两个方法的作用都一样,都能够监听ServletContext初始化事件,但用法上面有些不一样,例如前者要比后者早触发,前者的实现类需要放在一个模块中,关于模块和其它一些区别的地方不再叙述。

tomcat使用addApplicationEventListener和addApplicationLifecycleListener这两个方法,区分存储在两个列表里。

if (t instanceof ServletContextAttributeListener
|| t instanceof ServletRequestListener
|| t instanceof ServletRequestAttributeListener
|| t instanceof HttpSessionIdListener
|| t instanceof HttpSessionAttributeListener) {
context.addApplicationEventListener(t);
match = true;
} if (t instanceof HttpSessionListener ||
    (t instanceof ServletContextListener
      && newServletContextListenerAllowed)) {
context.addApplicationLifecycleListener(t);
match = true;
}

虽然传入的参数类型限制在EventListener类型,但实际上动态添加的类型只有这七类:

  1. ServletContextAttributeListener
  2. ServletRequestListener
  3. ServletRequestAttributeListener
  4. HttpSessionIdListener
  5. HttpSessionAttributeListener
  6. HttpSessionListener
  7. ServletContextListener

其中ServletContextListener,是受到newServletContextListenerAllowed变量的限制。

这个变量默认为true,在调用ServletContainerInitializer#onStartup方法时,仍然是true。

但在调用ServletContextListener#contextInitialized方法之前,这变量就会变成false,调用完后也一直保持着false。

也就是说,如果想通过动态添加监听器ServletContextListener的方式,只能在ServletContainerInitializer#onStartup的方法中添加。

其实简单的总结就是,ServletContextListener作为一个监听ServletContext的初始化,不能在这时候再添加这样的监听器,有什么事没做完的可以现在完成,非要搞什么推迟一下完成,是不是有点傻。

看到了么,最后那些未添加的监听器,都会接受末日审判。

if (match)
return; if (t instanceof ServletContextListener) {
throw new IllegalArgumentException(
    sm.getString("applicationContext.addListener.iae.sclNotAllowed",
    t.getClass().getName()));
} else {
throw new IllegalArgumentException(
    sm.getString("applicationContext.addListener.iae.wrongType",
    t.getClass().getName()));
}

完整源码:

 public <T extends EventListener> void addListener(T t) {
if (!context.getState().equals(LifecycleState.STARTING_PREP)) {
throw new IllegalStateException(sm.getString("applicationContext.addListener.ise", getContextPath()));
} boolean match = false; if (t instanceof ServletContextAttributeListener
|| t instanceof ServletRequestListener
|| t instanceof ServletRequestAttributeListener
|| t instanceof HttpSessionIdListener
|| t instanceof HttpSessionAttributeListener) {
context.addApplicationEventListener(t);
match = true;
} if (t instanceof HttpSessionListener || (t instanceof ServletContextListener && newServletContextListenerAllowed)) {
context.addApplicationLifecycleListener(t);
match = true;
} if (match)
return; if (t instanceof ServletContextListener) {
throw new IllegalArgumentException(sm.getString("applicationContext.addListener.iae.sclNotAllowed", t.getClass().getName()));
} else {
throw new IllegalArgumentException(sm.getString("applicationContext.addListener.iae.wrongType", t.getClass().getName()));
}
}

tomcat实现ServletContext的addListener方法的源码解说(原创)的更多相关文章

  1. Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘

    Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘 package com.parllay.scala.dataset /** * Created by richard ...

  2. [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析

    String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识,  ...

  3. Pycharm中查看方法的源码

    方法1.鼠标放在函数上,Ctrl+B,看源码 方法2.将光标移动至要查看的方法处,按住ctrl 键,点击鼠标左键,即可查看该方法的源码.

  4. 如何查看laravel门脸类包含方法的源码

    以Route门脸类为例,我们定义路由时使用的就是Route门脸类,例如我们在web.php中定义的路由 use Illuminate\Support\Facades\Route; Route::get ...

  5. 《JAVA高并发编程详解》-Thread start方法的源码

    Thread start方法的源码:

  6. Tomcat各个版本的下载地址包括源码

    Tomcat各个版本的下载地址包括源码: http://archive.apache.org/dist/tomcat **************** 选择版本 **************** ** ...

  7. HttpServlet中service方法的源码解读

    前言     最近在看<Head First Servlet & JSP>这本书, 对servlet有了更加深入的理解.今天就来写一篇博客,谈一谈Servlet中一个重要的方法-- ...

  8. beego 0.9.0 中智能路由AutoRouter的使用方法及源码解读

    了解beego的开发者肯定知道,beego的路由设计来源于sinatra,原来是不支持自动路由的,每一个路由都要自己配置的,如: type MainController struct { beego. ...

  9. Tomcat 调优之从 Linux 内核源码层面看 Tcp backlog

    前两天看到一群里在讨论 Tomcat 参数调优,看到不止一个人说通过 accept-count 来配置线程池大小,我笑了笑,看来其实很多人并不太了解我们用的最多的 WebServer Tomcat,这 ...

随机推荐

  1. 升级到win8.1右键响应慢

    网上很多资料都是在显卡上做文章,试了N次确定不是这个问题. 后来查到这个好用了.以管理员身份运行 下面代码保存bat即可 regsvr32 /u /s igfxpph.dll reg delete H ...

  2. PHP中实现MySQL嵌套事务的两种解决方案

    PHP中实现MySQL嵌套事务的两种解决方案 一.问题起源 在MySQL的官方文档中有明确的说明不支持嵌套事务: Transactions cannot be nested. This is a co ...

  3. 如何让MVC6在IIS上面跑

    asp.net5的MVC6发布出来的结果和MVC5之前版本的相差太远了,直接在本地的IIS服务器上面是不可能运行的. 看了汤姆大叔的MVC6项目发布与部署,讲了很多丰富的知识点.但是对于立即要解决问题 ...

  4. 安装RPM包或者安装源码包

    本系列的博客来自于:http://www.92csz.com/study/linux/ 在此,感谢原作者提供的入门知识 这个系列的博客的目的在于将比较常用的liunx命令从作者的文章中摘录下来,供自己 ...

  5. MySql Windws 下自动备份脚本

    这几天正在做一个  使用MySQL数据库的项目,目前项目已经完成了,当部署好项目之后,正在考虑如何自动备份MySql数据库的问题,我在网上找了一下资料终于解决了,特此记录一下. @echo off e ...

  6. hadoop+hive使用中遇到的问题汇总

    问题排查方式  一般的错误,查看错误输出,按照关键字google 异常错误(如namenode.datanode莫名其妙挂了):查看hadoop($HADOOP_HOME/logs)或hive日志 h ...

  7. SqlServer2012 数据库的同步之发布+订阅

    文章参考了百度过的文章,因为版本不同,操作中也遇到了很多问题,现在整理一下,希望对各位朋友有所帮助. 发布订阅份为两个步骤:1.发布.2订阅.首先在数据源数据库服务器上对需要同步的数据进行发布,然后在 ...

  8. Backbone源码解析(四):View(视图)模块

    View视图故名思义,它控制的是界面.我们可以把一个大的网页分成很多部分的视图,按照backbone的架构,每一个视图对应都是一个对象,我们可以通过元素的钩子(id或者class或者其他选择器)把它们 ...

  9. Java多线程14:生产者/消费者模型

    什么是生产者/消费者模型 一种重要的模型,基于等待/通知机制.生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点: ...

  10. 在WebApi中基于Owin OAuth使用授权发放Token

    如何基于Microsoft.Owin.Security.OAuth,使用Client Credentials Grant授权方式给客户端发放access token? Client Credentia ...