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. [原] XAF How can I change XafDisplayNameAttribute dynamically

    void ViewControlsCreated(object sender, EventArgs e) { foreach (StringPropertyEditor item in view.Ge ...

  2. 今天自己解决了两个问题(IE10 type slow ChromeDriver erro)

    都是通过google解决的,其实本应该很快解决,可是因自己粗心,大写小错了,加上java基础不过关, "webdriver.chrome.driver"中的webdriver应是全 ...

  3. map 遍历

    //最常规的一种遍历方法,最常规就是最常用的,虽然不复杂,但很重要,这是我们最熟悉的,就不多说了!! public static void work(Map<String, Student> ...

  4. 走读openwrt的shell的总结【转】

    原文:http://blog.chinaunix.net/uid-26598889-id-3060543.html ". /etc/diag.sh" 就是将/etc/diag.sh ...

  5. Runtime 动态加载方法

    动态加载 #import"ViewController.h" #import"Person.h" @interfaceViewController() @end ...

  6. display:block 不起作用

    jquery中$("#Main").css("display","none"); $("#Day").css('disp ...

  7. 跟visual studio 集成的git插件

    目前有三个,git extension,微软的 visual studio tools for git extension,还有git source control provider 经测试,最好用的 ...

  8. SQLServer 获取第几周开始日期

    不多说直接上code DECLARE @CurrDay DATETIME=GETDATE() --SET @CurrDay=CAST(('2013-01-10')AS DATETIME) --SET ...

  9. .Net Core CLI windows安装

    下载官方的msi安装包official MSI installer双击安装就可以了. 默认会安装到C:\Program Files\dotnet\目录下,如果找不到可以用命令 where dotnet ...

  10. 我的ORM之五-- 事务

    我的ORM索引 单库事务与分布式事务 单库事务: 性能更好,应用于一个数据库时的场景,当数据库发生变化,如拆分为多个服务器,代码需要修改. 分布式事务:性能相对较差,但有更大的适用场景.当数据库发生变 ...