Java SPI、servlet3.0与@HandlesTypes源码分析
关于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源码分析的更多相关文章
- Android7.0 Phone应用源码分析(二) phone来电流程分析
接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...
- Android7.0 Phone应用源码分析(一) phone拨号流程分析
1.1 dialer拨号 拨号盘点击拨号DialpadFragment的onClick方法会被调用 public void onClick(View view) { int resId = view. ...
- Android7.0 Phone应用源码分析(三) phone拒接流程分析
本文主要分析Android拒接电话的流程,下面先来看一下拒接电话流程时序图 步骤1:滑动按钮到拒接图标,会调用到AnswerFragment的onDecline方法 com.android.incal ...
- Android7.0 Phone应用源码分析(四) phone挂断流程分析
电话挂断分为本地挂断和远程挂断,下面我们就针对这两种情况各做分析 先来看下本地挂断电话的时序图: 步骤1:点击通话界面的挂断按钮,会调用到CallCardPresenter的endCallClicke ...
- lesson2:java阻塞队列的demo及源码分析
本文向大家展示了java阻塞队列的使用场景.源码分析及特定场景下的使用方式.java的阻塞队列是jdk1.5之后在并发包中提供的一组队列,主要的使用场景是在需要使用生产者消费者模式时,用户不必再通过多 ...
- Java -- 基于JDK1.8的ArrayList源码分析
1,前言 很久没有写博客了,很想念大家,18年都快过完了,才开始写第一篇,争取后面每周写点,权当是记录,因为最近在看JDK的Collection,而且ArrayList源码这一块也经常被面试官问道,所 ...
- Java ThreadPoolExecutor线程池原理及源码分析
一.源码分析(基于JDK1.6) ThreadExecutorPool是使用最多的线程池组件,了解它的原始资料最好是从从设计者(Doug Lea)的口中知道它的来龙去脉.在Jdk1.6中,Thread ...
- Java入门系列之集合HashMap源码分析(十四)
前言 我们知道在Java 8中对于HashMap引入了红黑树从而提高操作性能,由于在上一节我们已经通过图解方式分析了红黑树原理,所以在接下来我们将更多精力投入到解析原理而不是算法本身,HashMap在 ...
- Java入门系列之集合Hashtable源码分析(十一)
前言 上一节我们实现了散列算法并对冲突解决我们使用了开放地址法和链地址法两种方式,本节我们来详细分析源码,看看源码中对于冲突是使用的哪一种方式以及对比我们所实现的,有哪些可以进行改造的地方. Hash ...
随机推荐
- 任务分线程实现(java)
1.创建一个类,用户存储信息 public class Users { private String userid; private String username; public Users() { ...
- b161: NOIP2007 4.Hanoi双塔问题
zerojudge 汉诺塔?图片问度娘 b161: NOIP2007 4.Hanoi双塔问题 题目: 给定A.B.C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都 ...
- Linux之vim、压缩与解压缩
终有一种方法适合你!
- java架构之路-(设计模式)五种创建型模式之单例模式
设计模式自身一直不是很了解,但其实我们时刻都在使用这些设计模式的,java有23种设计模式和6大原则. 设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可 ...
- Spark比MR快是因为在内存中计算?错!
MapReduce 就像一台又慢又稳的老爷车,虽然距离 MapReduce 面市到现在已经过去了十几年的时间,但它始终没有被淘汰,任由大数据技术日新月异.蓬蓬勃勃.花里胡哨地发展,这个生态圈始终有它的 ...
- centos 搭建SVN服务器简单流程
yum -y install subversion mkdir -p /work/svn && cd /work/svn //创建版本库 svnadmin create test -- ...
- [C++] 类的使用(1)
1.类的基本思想是数据抽象和封装.数据抽象是一种依赖于接口和实现分离的编程(以及设计)技术. 2.常量对象,以及常量对象的引用或指针都只能调用常量成员函数.因为非常量成员函数有可能修改其作用的对象,与 ...
- 【POJ - 3723 】Conscription(最小生成树)
Conscription Descriptions 需要征募女兵N人,男兵M人. 每招募一个人需要花费10000美元. 如果已经招募的人中有一些关系亲密的人,那么可以少花一些钱. 给出若干男女之前的1 ...
- Spring入门(十四):Spring MVC控制器的2种测试方法
作为一名研发人员,不管你愿不愿意对自己的代码进行测试,都得承认测试对于研发质量保证的重要性,这也就是为什么每个公司的技术部都需要质量控制部的原因,因为越早的发现代码的bug,成本越低,比如说,Dev环 ...
- SQL数据库各种查询建表插入集合-待续持续更新
创建表 drop table student; DROP table Course; DROP table sc; CREATE TABLE student ( sid integer PRIMARY ...