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這個注解的呢。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM