关于Java SPI与servlet3.0的应用,这里说的很精炼,链接地址如下。

https://blog.csdn.net/pingnanlee/article/details/80940993

以Tomcat8.5.31对Servlet的实现为例,简单提一点,Tomcat获取ServletContainerInitializer的实现类是在org.apache.catalina.startup.ContextConfig.webConfig() 中,Step 3调用processServletContainerInitializers(),

使用了自己的WebappServiceLoader,解释为A variation of Java's JAR ServiceLoader。

顺带一提tomcat启动时webConfig() 的调用链:

Tomcat.start()->各种代理的start()->org.apache.catalina.core.StandardContext.startInternal->LifecycleBase.fireLifecycleEvent->org.apache.catalina.startup.ContextConfig.lifecycleEvent->configureStart->webConfig

另:感叹一下tomcat的源码中,每一个方法都好长,和spring源码的深层次相比简直各有千秋,以及那个叫做ok的boolean 变量,可能相比用异常来表示更为直观吧。

@HandlesTypes的实现原理:

首先这个注解最开始令我非常困惑,他的作用是将注解指定的Class对象作为参数传递到onStartup(ServletContainerInitializer)方法中。

然而这个注解是要留给用户扩展的,他指定的Class对象并没有要继承ServletContainerInitializer,更没有写入META-INF/services/的文件(也不可能写入)中,那么Tomcat是怎么扫描到指定的类的呢。

答案是Byte Code Engineering Library (BCEL),这是Apache Software Foundation 的Jakarta 项目的一部分,作用同ASM类似,是字节码操纵框架。

webConfig() 在调用processServletContainerInitializers()时记录下注解的类名,然后在Step 4和Step 5中都来到processAnnotationsStream这个方法,使用BCEL的ClassParser在字节码层面读取了/WEB-INF/classes和某些jar(应该可以在叫做fragments的概念中指定)中class文件的超类名和实现的接口名,判断是否与记录的注解类名相同,若相同再通过org.apache.catalina.util.Introspection类load为Class对象,最后保存起来,于Step 11中交给org.apache.catalina.core.StandardContext,也就是tomcat实际调用

ServletContainerInitializer.onStartup()的地方。

至此,谜团终于解开。

不过还有一个小疑问,StandardContext存放@HandlesTypes的对象叫做Map<ServletContainerInitializer,Set<Class<?>>> initializers,他的addServletContainerInitializer方法除了webConfig()以外,还被TomcatEmbeddedServletContainerFactory.addJasperInitializer和TomcatEmbeddedServletContainerFactory.configureContext调用,不知道运行起来是否有多余的class混入其中。也难怪spring要在SpringServletContainerInitializer.onstart的处理中这样注释的原因了吧:D

  // Be defensive: Some servlet containers provide us with invalid classes,
  // no matter what @HandlesTypes says...

不知道其他Servlet,比如Jetty引擎,是怎么实现@HandlesTypes这个注解的呢。

Java SPI、servlet3.0与@HandlesTypes源码分析的更多相关文章

  1. Android7.0 Phone应用源码分析(二) phone来电流程分析

    接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...

  2. Android7.0 Phone应用源码分析(一) phone拨号流程分析

    1.1 dialer拨号 拨号盘点击拨号DialpadFragment的onClick方法会被调用 public void onClick(View view) { int resId = view. ...

  3. Android7.0 Phone应用源码分析(三) phone拒接流程分析

    本文主要分析Android拒接电话的流程,下面先来看一下拒接电话流程时序图 步骤1:滑动按钮到拒接图标,会调用到AnswerFragment的onDecline方法 com.android.incal ...

  4. Android7.0 Phone应用源码分析(四) phone挂断流程分析

    电话挂断分为本地挂断和远程挂断,下面我们就针对这两种情况各做分析 先来看下本地挂断电话的时序图: 步骤1:点击通话界面的挂断按钮,会调用到CallCardPresenter的endCallClicke ...

  5. lesson2:java阻塞队列的demo及源码分析

    本文向大家展示了java阻塞队列的使用场景.源码分析及特定场景下的使用方式.java的阻塞队列是jdk1.5之后在并发包中提供的一组队列,主要的使用场景是在需要使用生产者消费者模式时,用户不必再通过多 ...

  6. Java -- 基于JDK1.8的ArrayList源码分析

    1,前言 很久没有写博客了,很想念大家,18年都快过完了,才开始写第一篇,争取后面每周写点,权当是记录,因为最近在看JDK的Collection,而且ArrayList源码这一块也经常被面试官问道,所 ...

  7. Java ThreadPoolExecutor线程池原理及源码分析

    一.源码分析(基于JDK1.6) ThreadExecutorPool是使用最多的线程池组件,了解它的原始资料最好是从从设计者(Doug Lea)的口中知道它的来龙去脉.在Jdk1.6中,Thread ...

  8. Java入门系列之集合HashMap源码分析(十四)

    前言 我们知道在Java 8中对于HashMap引入了红黑树从而提高操作性能,由于在上一节我们已经通过图解方式分析了红黑树原理,所以在接下来我们将更多精力投入到解析原理而不是算法本身,HashMap在 ...

  9. Java入门系列之集合Hashtable源码分析(十一)

    前言 上一节我们实现了散列算法并对冲突解决我们使用了开放地址法和链地址法两种方式,本节我们来详细分析源码,看看源码中对于冲突是使用的哪一种方式以及对比我们所实现的,有哪些可以进行改造的地方. Hash ...

随机推荐

  1. Airflow: TypeError can't pickle memoryview objects

    apache-airflow1.9.0 + python3 + rabbitmq + librabbitmq2.0.0 相关配置如下: broker_url = amqp://cord:123456@ ...

  2. eclipse查看.class文件

    要使用jd-gui.exe反编译程序 步骤:window-preferences-general-editors-file associations, 如下图 上面的框选中,*.class witho ...

  3. FBCTF平台安装

    一言难尽 = =开始不知道FBCTF只能安装在Ubuntu,在本地搭建半天好不容易弄起了PHP环境,打开错误,后来才知道只能在Ubuntu 14.04 LTS下安装= = FBCTF是Facebook ...

  4. 最近学习到的Lambda表达式

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 中秋去了躺上海,在外滩上打了个卡: 紧接着学了一下J ...

  5. 2018年蓝桥杯java b组第五题

    标题:快速排序 以下代码可以从数组a[]中找出第k小的元素. 它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的. 请仔细阅读分析源码,填写划线部分缺失的内容. 我在使用(a, l, r, ...

  6. 制定一个学习liunx的目标

        制定一个学习liunx的目标       学习目标方法 1.在这五个月的学习时间里,制定一套自己的学习方式. 2.养成做笔记以及写博客的习惯 . 3.坚持上课前预习,自习时间总结 . 4.紧跟 ...

  7. 从二叉查找树到B+树中间的各种树

    高强度训练第十八天总结: 二叉查找树: 二叉查找树就是左结点小于根节点,右结点大于根节点的一种排序树,也叫二叉搜索树.也叫BST,英文Binary Sort Tree. 就长下面这吊样 查找步骤 在二 ...

  8. append追加的html片段,添加点击事件没有反应,解决!

    对于追加的元素来说,属于未来展现的内容,我们此时不能使用一般点击事情处理,需要用未来事件绑定. 例如:我点击车牌号显示车辆详情,如下绑定. //绑定未来元素 $("body").d ...

  9. Docker系列(一):容器监控工具Weave Scope安装

    项目进行容器化之后,配套的基础设施包括监控.编排.管理等都需要进行一并完善.这里也是自己一边学习一边进行记录. Weave Scope 的最大特点是会自动生成一张 Docker 容器地图,让我们能够直 ...

  10. Shell之变量

    目录 Shell之变量 参考 变量命名规则 变量语法规范 四种变量类型 系统变量 特殊变量 变量的使用 变量内容的删除和替换 Shell之变量