日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Tomcat中的可插拔以及SCI的實現(xiàn)原理

常用計算機(jī)的朋友一定記得, U盤,硬盤等設(shè)備流行的時候,當(dāng)時對于這項技術(shù)的介紹是熱插拔。

成都創(chuàng)新互聯(lián)服務(wù)項目包括紫云網(wǎng)站建設(shè)、紫云網(wǎng)站制作、紫云網(wǎng)頁制作以及紫云網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,紫云網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到紫云省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

這個介紹最主要的是想說明這些外接設(shè)備的便利性,同時也說明他們的無侵入性。

在 Servlet 3.x 的時候,也增加了這種可插拔的能力,讓我們在項目組織上,可以接近于設(shè)備的接入。

例如在 Servlet 3 之前只能在web.xml中聲明 Servlet、Filter 等, 在 Servlet 3 之后,除了 @WebFilter 這種注解的方式外

還可以在單獨的fragement 打包文件,在web-fragement.xml 聲明的組件,容器啟動時就會掃描到。

當(dāng)然,也可以在運行時動態(tài)的添加Servlet/Filter,即Servlet 3.x中的 Dynamic Servlet。

除此之外,對于 SCI 的實現(xiàn),提供的也是這種能力。通過對標(biāo)準(zhǔn)接口的實現(xiàn),在特定階段觸發(fā)動作執(zhí)行。

比如我們前面說到的 Spring Boot 的應(yīng)用,其以 Jar 的方式啟動,來啟動容器,提供服務(wù)的實現(xiàn),就是通過SCI的方式來觸發(fā)的。Tomcat 是怎樣處理 SpringBoot應(yīng)用的?

甚至容器自行的一些組件,如JSP Container的實現(xiàn),也使用 SCI 的能力來進(jìn)行實現(xiàn)。

我們本次主要來分析 Tomcat 通過 SCI 實現(xiàn)的這種可插拔性(pluggability)。

首先,什么是 SCI?

全稱 ServletContainerInitializer,是一個用于接收Web 應(yīng)用在啟動階段通知的接口,再根據(jù)通知進(jìn)行一些編程式的處理,比如動態(tài)注冊Servlet、Filter等。

如何使用?

SCI 的使用也比較容易,將實現(xiàn) ServletContainerInitializer 接口的類增加 HandlesTypes ,注解內(nèi)指定的一系列類,接口,注解的 class 集合, 會在啟動階段 class 掃描的時候,將與這些 class 相關(guān)的 文件都掃描出來,做為 SCI 的onStartup方法參數(shù)傳遞。

這一類實現(xiàn)了 SCI 的接口,如果做為獨立的包發(fā)布,在打包時,會在 JAR 文件的 META-INF/services/javax.servlet.ServletContainerInitializer 文件中進(jìn)行注冊。 容器在啟動時,就會掃描所有帶有這些注冊信息的類進(jìn)行解析,啟動時會調(diào)用其 onStartup方法。

這就是可插拔性? 類加載***個表示不服?!拔疫€可以熱替換啊!” 這里是有區(qū)別的, 熱替換,類加載,都是根據(jù)限定的名稱去加載,并沒有相關(guān)的標(biāo)準(zhǔn)去加載未知的內(nèi)容,而這里SCI則根據(jù)約定的標(biāo)準(zhǔn),掃描META-INF中包含注冊信息的 class 并在啟動階段調(diào)用其onStartup,這就是區(qū)別啊。

百聞不如一見,光說不練假把式,我們來看除了前面說的 Spring Boot 外,誰還在用SCI。

我們先來看在 Tomcat 關(guān)于 WebSocket的實現(xiàn)。

 
 
 
  1. @HandlesTypes({ServerEndpoint.class, ServerApplicationConfig.class,
  2.         Endpoint.class})
  3. public class WsSci implements ServletContainerInitiali

這里的HandlesTypes里指明了實現(xiàn) WebSocket需要關(guān)注的幾個類,將通過注解方式聲明WebSocket和通過編程方式聲明都包含了進(jìn)來。

在應(yīng)用啟動時,觸發(fā)onStartup方法執(zhí)行,然后初始化WebSocket相關(guān)的內(nèi)容,解析注解等

 
 
 
  1. public void onStartup(Set> clazzes, ServletContext ctx)
  2.         throws ServletException {
  3.     WsServerContainer sc = init(ctx, true);
  4.     if (clazzes == null || clazzes.size() == 0) {
  5.         return;
  6.     }
  7.     // Group the discovered classes by type
  8.     Set serverApplicationConfigs = new HashSet<>();
  9.     Set> scannedEndpointClazzes = new HashSet<>();
  10.     Set> scannedPojoEndpoints = new HashSet<>();

這里注意,由于WebSocket并不是為特定應(yīng)用提供的,而是做為容器的基礎(chǔ)能力提供,并且其是在 Tomcat_home/lib 目錄內(nèi),因此,每個應(yīng)用在啟動時,都會觸發(fā) WebSocket,來解析其是否包含了對于 WebSocket的引用,從而為其提供支持。

這一條流程是如何串連的呢?我們前面的文章曾分析過應(yīng)用的部署,提到過HostConfig, ContextConfig這些類。 應(yīng)用在啟動時startup事件會觸發(fā) ContextConfig 這個Listener 的執(zhí)行,此時會掃描應(yīng)用包含的JAR文件,解析web-fragement.xml等, 這其中也包含對于SCI實現(xiàn)的解析。

 
 
 
  1. // Step 11. Apply the ServletContainerInitializer config to the
  2. // context
  3. if (ok) {
  4.     for (Map.Entry
  5.             Set>> entry :
  6.                 initializerClassMap.entrySet()) {
  7.         if (entry.getValue().isEmpty()) {
  8.             context.addServletContainerInitializer(
  9.                     entry.getKey(), null);
  10.         } else {
  11.             context.addServletContainerInitializer(
  12.                     entry.getKey(), entry.getValue());
  13.         }
  14.     }
  15. }

這里解析出來的類會添加到Context中,在應(yīng)用啟動階段,會調(diào)用每個SCI實現(xiàn)的onStartup方法

 
 
 
  1. // Call ServletContainerInitializers
  2. for (Map.Entry>> entry :
  3.     initializers.entrySet()) {
  4.     try {
  5.         entry.getKey().onStartup(entry.getValue(),
  6.                 getServletContext());
  7.     } catch (ServletException e) {
  8.         log.error(sm.getString("standardContext.sciFail"), e);
  9.         ok = false;
  10.         break;
  11.     }
  12. }

SpringBoot 也是這樣被點燃的

 
 
 
  1. public void onStartup(ServletContext servletContext) throws ServletException {
  2.     this.logger = LogFactory.getLog(this.getClass());
  3.     WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
  4.     if(rootAppContext != null) {
  5.         servletContext.addListener(new ContextLoaderListener(rootAppContext) {
  6.             public void contextInitialized(ServletContextEvent event) {
  7.             }
  8.         });
  9.     } else {
  10.         this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
  11.     }
  12. }

而且 JSP 的容器也開始使用這種方式進(jìn)行工廠的初始化,以便于后面繼續(xù)使用。

 
 
 
  1. /**
  2.  * Initializer for the Jasper JSP Engine.
  3.  */
  4. public class JasperInitializer implements ServletContain

那這個Jasper 的SCI,難道就為了初始化一個工廠嗎?這和 Servlet 3.x之前也沒啥區(qū)別是吧?

別急,我們繼續(xù)看其onStartup方法

 
 
 
  1. public void onStartup(Set> types, ServletContext context) throws ServletException {
  2.  
  3. ...
  4.     // scan the application for TLDs
  5.     TldScanner scanner = newTldScanner(context, true, validate, blockExternal);
  6.     try {
  7.         scanner.scan();
  8.     } catch (IOException | SAXException e) {
  9.         throw new ServletException(e);
  10.     }

原來將 TLD文件的掃描移到了這里, WebContainer 只需要處理web.xml 和 web-fragement.xml的處理即可, JSP 的工作就交給他來做嘛,各司其職,挺好的。用 spec 的話來形容,是更好的分離了 Web Container 和 JSP Container職責(zé)。

【本文為專欄作者“侯樹成”的原創(chuàng)稿件,轉(zhuǎn)載請通過作者微信公眾號『Tomcat那些事兒』獲取授權(quán)】


標(biāo)題名稱:Tomcat中的可插拔以及SCI的實現(xiàn)原理
轉(zhuǎn)載注明:http://www.5511xx.com/article/cosegcc.html