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] 多级联列表显示

    XAF给的例子已经实现,详细可查看例子中的代码. 工作车间--工作中心--机器

  2. Html总结及日志目录

    Html就是超文本标记语言的简写,是最基础的网页语言,代码都是由标签所组成,不用区分大小写. 1. Html代码由<html>开始</html>结束.里面由头部分<hea ...

  3. (转C#中Enum用法小结)

    enums枚举是值类型,数据直接存储在栈中,而不是使用引用和真实数据的隔离方式来存储. (1)默认情况下,枚举中的第一个变量被赋值为0,其他的变量的值按定义的顺序来递增(0,12,3...),因此以下 ...

  4. linux-13基础命令之-touch,mkdir

    1.  touch 命令 用于创建空白文件与修改文件时间,格式:touch[选项][文件]: linux 下文件时间有三种 @1.更改时间(mtime):内容修改时间: @2.更改权限(ctime): ...

  5. java servlet之过滤器1(解决jsp之间POST方式数据传递乱码)

    首先,看看没有解决乱码的效果,新建两个jsp页面(a.jsp跳转到b.jsp). <form action="b.jsp" method="post"&g ...

  6. 【原创】还原Hyper-V 到一个新的虚拟机

    Context: I need to restore VM31 backup (via 'Windows Server Backup' tool) as another new Hyper-V mac ...

  7. Xamarin.Android经验之谈

    1.Fragment如何做到显示才加载数据 有些界面我们会采用套用多个Fragment来显示的效果,但是我们不会在一显示这个活动的时候就把所有的Fragment加载并加载数据,而是会让显示出来的Fra ...

  8. 基于SignalR的web端即时通讯 - ChatJS

    先看下效果. ChatJS 是基于SignalR实现的Web端IM,界面风格模仿的是“脸书”,可以很方便的集成到已有的产品中. 项目官网:http://chatjs.net/ github地址:htt ...

  9. 关于RPC与MQ异同的理解

    最近看了一些资料,回顾过去项目的经验,梳理自己对两者异同的理解: 相同: 1.都利于大型系统的解耦: 2.都提供子系统之间的交互,特别是异构子系统(如java\node等不同开发语言): 不同: 1. ...

  10. EF6(CodeFirst)+MySql开发遇到的坑

    最近一不小心偷个懒就已经过了好几个月了,真是惭愧惭愧,出来混终究是要还的,我还是把”脱坑指南“写完吧,-_-~~.点我打开上篇博客 0x001.架构名”dbo”の殇 坑之首也,当提架构名,在mssql ...