日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

詳解從源碼分析tomcat如何調(diào)用Servlet的初始化

瀏覽:372日期:2023-03-19 16:50:59
目錄
  • 引言
  • 一、代碼啟動(dòng)tomcat
  • 二、tomcat框架
  • 三、創(chuàng)建容器(addWebapp())
    • 3.1 方法 調(diào)用流程圖
    • 3.2 源碼分析
  • 四、啟動(dòng)容器(tomcat.start())
    • 4.1、方法調(diào)用流程圖
    • 4.2、源碼分析
  • 五、總結(jié)

    引言

    上一篇博客我們將tomcat源碼在本地成功運(yùn)行了,所以在本篇博客中我們從源碼層面分析,tomcat在啟動(dòng)的過(guò)程中,是如何初始化servlet容器的。我們平常都是將我們的服務(wù)部署到 tomcat中,然后修改一下配置文件,啟動(dòng)就可以對(duì)外提供 服務(wù)了,但是我們對(duì)于其中的一些流程并不是非常的了解,例如如何加載的web.xml等。這是我們分析servlet 和 sringMVC必不可少的過(guò)程。

    注釋源碼地址:https://github.com/good-jack/tomcat_source/tree/master

    一、代碼啟動(dòng)tomcat

    平常我們不論是Windows還是linux,我們都是通過(guò)腳本來(lái)啟動(dòng)tomcat,這對(duì)于我們分析源碼不是很友好,所以我們 需要通過(guò)代碼啟動(dòng),啟動(dòng)代碼如下:

    Tomcat tomcat = new Tomcat();tomcat.setPort(8080);//new 出各層容器,并且維護(hù)各層容器的關(guān)系tomcat.addWebapp("/","/");tomcat.start();//阻塞監(jiān)聽(tīng)端口tomcat.getServer().await();

    啟動(dòng)代碼還是非常非常簡(jiǎn)單,從代碼中我們就可以看出,我們本篇博客主要分析的就是 addWebapp()方法和start()方法,通過(guò)這兩個(gè)方法我們就可以找到servlet容器是在什么時(shí)候被初始化的。

    二、tomcat框架

    在我們進(jìn)行分析上面兩個(gè)方法之前,我們先總結(jié)一下tomcat的基礎(chǔ)框架,其實(shí)從我們非常熟悉的 server.xml配置文件中就可以知道,tomcat就是一系列父子容器組成:

    Server ---> Service --> Connector Engine addChild---> context(servlet容器) ,這就是我們從配置文件中分析出來(lái)的幾個(gè)容器,tomcat啟動(dòng)時(shí)候就是逐層啟動(dòng)容器。

    三、創(chuàng)建容器(addWebapp())

    3.1 方法 調(diào)用流程圖

    上面的流程圖就是,從源碼中逐步分析出來(lái)的幾個(gè)重要的方法,這對(duì)于我們分析源碼非常有幫助。

    3.2 源碼分析

    1)通過(guò)反射獲得configContext監(jiān)聽(tīng)器

    方法路徑:package org.apache.catalina.startup.Tomcat.addWebapp(Host host, String contextPath, String docBase);

         public Context  addWebapp(Host host, String contextPath, String docBase) {//通過(guò)反射獲得一個(gè)監(jiān)聽(tīng)器  ContextConfig,//通過(guò)反射得到的一定是LifecycleListener的一個(gè)實(shí)現(xiàn)類,進(jìn)入getConfigClass得到實(shí)現(xiàn)類(org.apache.catalina.startup.ContextConfig)LifecycleListener listener = null;try {    Class<?> clazz = Class.forName(getHost().getConfigClass());    listener = (LifecycleListener) clazz.getConstructor().newInstance();} catch (ReflectiveOperationException e) {    // Wrap in IAE since we can"t easily change the method signature to    // to throw the specific checked exceptions    throw new IllegalArgumentException(e);} return addWebapp(host, contextPath, docBase, listener);    }

    2) 獲得一個(gè)context容器(StandardContext)

    在下面代碼中,createContext()方法通過(guò)反射加載StandardContext容器,并且將設(shè)置監(jiān)聽(tīng)ContextConfig, ctx.addLifecycleListener(config);

    public Context addWebapp(Host host, String contextPath, String docBase,    LifecycleListener config) { silence(host, contextPath); //獲得一個(gè)context容器(StandardContext)Context ctx = createContext(host, contextPath);ctx.setPath(contextPath);ctx.setDocBase(docBase); if (addDefaultWebXmlToWebapp) {    ctx.addLifecycleListener(getDefaultWebXmlListener());} ctx.setConfigFile(getWebappConfigFile(docBase, contextPath));//把監(jiān)聽(tīng)器添加到context中去ctx.addLifecycleListener(config); if (addDefaultWebXmlToWebapp && (config instanceof ContextConfig)) {    // prevent it from looking ( if it finds one - it"ll have dup error )    ((ContextConfig) config).setDefaultWebXml(noDefaultWebXmlPath());} if (host == null) {    //getHost會(huì)逐層創(chuàng)建容器,并維護(hù)容器父子關(guān)系    getHost().addChild(ctx);} else {    host.addChild(ctx);} return ctx;    }

    3)維護(hù)各層容器

    getHost()方法中得到各層容器,并且維護(hù)父親容器關(guān)系,其中包括,server容器、Engine容器。并且將StandardContext容器通過(guò)getHost().addChild(ctx); 調(diào)用containerBase中的addChild()方法維護(hù)在 children 這個(gè)map中。

      public Host getHost() {//將每一層的容器都new 出來(lái)Engine engine = getEngine();if (engine.findChildren().length > 0) {    return (Host) engine.findChildren()[0];} Host host = new StandardHost();host.setName(hostname);//維護(hù)tomcat中的父子容器getEngine().addChild(host);return host;    }

    getEngine().addChild(host); 方法選擇調(diào)用父類containerBase中的addChild方法

      @Override    public void addChild(Container child) {if (Globals.IS_SECURITY_ENABLED) {    PrivilegedAction<Void> dp =new PrivilegedAddChild(child);    AccessController.doPrivileged(dp);} else {    //這里的child 參數(shù)是 context 容器    addChildInternal(child);}    }

    addChildInternal()方法的 核心代碼

     private void addChildInternal(Container child) { if( log.isDebugEnabled() )    log.debug("Add child " + child + " " + this);synchronized(children) {    if (children.get(child.getName()) != null)throw new IllegalArgumentException("addChild:  Child name "" +   child.getName() +   "" is not unique");    child.setParent(this);  // May throw IAE    children.put(child.getName(), child);    }

    四、啟動(dòng)容器(tomcat.start())

    4.1、方法調(diào)用流程圖

    4.2、源碼分析

    說(shuō)明:StandardServer 、StandardService、StandardEngine等容器都是繼承LifecycleBase

    所以這里是模板模式的經(jīng)典應(yīng)用

    1)逐層啟動(dòng)容器

    此時(shí)的server對(duì)應(yīng)的是我們前面創(chuàng)建的StandardServer

      public void start() throws LifecycleException {//防止server容器沒(méi)有創(chuàng)建getServer();//獲得connector容器,并且將得到的connector容器設(shè)置到service容器中g(shù)etConnector();//這里的start的實(shí)現(xiàn)是在 LifecycleBase類中實(shí)現(xiàn)//LifecycleBase方法是一個(gè)模板方法,在tomcat啟動(dòng)流程中非常關(guān)鍵server.start();    }

    2) 進(jìn)入start方法

    進(jìn)入LifecycelBase中的start方法,其中核心方法是startInternal。

    從上面我們知道現(xiàn)在我們調(diào)用的是StandardServer容器的startInternal()方法,所以我們這里選擇的是StandardServer

    方法路徑:org.apache.catalina.core.StandardServer.startInternal()

    protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null);setState(LifecycleState.STARTING); globalNamingResources.start(); // Start our defined Servicessynchronized (servicesLock) {    //啟動(dòng) service容器,一個(gè)tomcat中可以配置多個(gè)service容器,每個(gè)service容器都對(duì)應(yīng)這我們的一個(gè)服務(wù)應(yīng)用    for (Service service : services) {//對(duì)應(yīng) StandardService.startInternal()service.start();    }}    }

    從上面代碼中我們可以看出,啟動(dòng)server容器的時(shí)候需要啟動(dòng)子容器 service容器,從這里開(kāi)始就是容器 逐層向向內(nèi)引爆,所以接下來(lái)就是開(kāi)始依次調(diào)用各層容器的star方法。在這里就不在贅述。

    2)ContainerBase中的startInternal()方法 核心代碼,從這開(kāi)始啟動(dòng)StandardContext容器

     // Start our child containers, if any//在addWwbapp的流程中 addChild方法中加入的,所以這里需要找出來(lái)//這里找出來(lái)的就是 context 容器Container children[] = findChildren();List<Future<Void>> results = new ArrayList<>();for (Container child : children) {    //通過(guò)線程池 異步的方式啟動(dòng)線程池 開(kāi)始啟動(dòng) context容器,進(jìn)入new StartChild    results.add(startStopExecutor.submit(new StartChild(child)));}

    new StartChild(child)) 方法開(kāi)始啟動(dòng)StandardContext容器

        private static class StartChild implements Callable<Void> { private Container child; public StartChild(Container child) {    this.child = child;} @Overridepublic Void call() throws LifecycleException {    //開(kāi)始啟動(dòng)context,實(shí)際調(diào)用 StandardContext.startInternal()    child.start();    return null;}    }

    StandardContext.startInternal() 方法中的核心代碼:

       protected void fireLifecycleEvent(String type, Object data) {LifecycleEvent event = new LifecycleEvent(this, type, data);//lifecycleListeners 在addwebapp方法的第一步中,設(shè)置的監(jiān)聽(tīng)的 contextConfig對(duì)象for (LifecycleListener listener : lifecycleListeners) {    //這里調(diào)用的是 contextConfig的lifecycleEvent()方法    listener.lifecycleEvent(event);}    }

    進(jìn)入到 contextConfig中的lifecycleEvent()方法

    public void lifecycleEvent(LifecycleEvent event) { // Identify the context we are associated withtry {    context = (Context) event.getLifecycle();} catch (ClassCastException e) {    log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);    return;} // Process the event that has occurredif (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {    //完成web.xml的內(nèi)容解析    configureStart();} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {    beforeStart();} else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {    // Restore docBase for management tools    if (originalDocBase != null) {context.setDocBase(originalDocBase);    }} else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {    configureStop();} else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {    init();} else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {    destroy();}     }

    在上面方法中,完成對(duì)web.xml的加載和解析,同時(shí)加載xml中配置的servlet并且封裝成wrapper對(duì)象。

    3)、啟動(dòng)servlet容器,StandardContext.startInternal() 中的 loadOnStartup(findChildren())方法

    public boolean loadOnStartup(Container children[]) { // Collect "load on startup" servlets that need to be initializedTreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>();for (Container child : children) {    //這里的 Wrapper就是 我們前面封裝的 servlet    Wrapper wrapper = (Wrapper) child;    int loadOnStartup = wrapper.getLoadOnStartup();    if (loadOnStartup < 0) {continue;    }    Integer key = Integer.valueOf(loadOnStartup);    ArrayList<Wrapper> list = map.get(key);    if (list == null) {list = new ArrayList<>();map.put(key, list);    }    list.add(wrapper);} // Load the collected "load on startup" servletsfor (ArrayList<Wrapper> list : map.values()) {    for (Wrapper wrapper : list) {try {    //通過(guò) load 方法  最終會(huì)調(diào)用 servlet的init方法    wrapper.load();} catch (ServletException e) {    getLogger().error(sm.getString("standardContext.loadOnStartup.loadException",  getName(), wrapper.getName()), StandardWrapper.getRootCause(e));    // NOTE: load errors (including a servlet that throws    // UnavailableException from the init() method) are NOT    // fatal to application startup    // unless failCtxIfServletStartFails="true" is specified    if(getComputedFailCtxIfServletStartFails()) {return false;    }}    }}return true;     }

    通過(guò) load 方法 最終會(huì)調(diào)用 servlet的init方法。

    五、總結(jié)

    上面內(nèi)容就是整個(gè)tomcat是如何調(diào)用servlet初始化方法的流程,整個(gè)流程小編的理解,如果有錯(cuò)誤,歡迎指正,小編已經(jīng)在源碼中重要部分進(jìn)行了注釋,所以如果有需要的各位讀者,可以下載我的注釋 源碼,注釋源碼地址:

    https://github.com/good-jack/tomcat_source/tree/master

    到此這篇關(guān)于詳解從源碼分析tomcat如何調(diào)用Servlet的初始化的文章就介紹到這了,更多相關(guān)tomcat調(diào)用Servlet初始化內(nèi)容請(qǐng)搜索以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持!

    標(biāo)簽: Tomcat
    日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
    免费一区二区视频| 久久国产精品久久w女人spa| 一区二区精品| 免费人成在线不卡| 国产调教精品| 亚洲永久精品唐人导航网址| 午夜国产精品视频免费体验区| 亚洲精品四区| 中文一区一区三区高中清不卡免费| 国产主播一区| 久久国产精品毛片| 麻豆精品视频在线| 久久精品123| 欧美精品黄色| 成人在线黄色| 亚洲人成高清| 亚洲h色精品| 国产精品视频一区二区三区综合| 岛国精品一区| 日本午夜精品久久久| 欧美freesex黑人又粗又大| 亚洲精品第一| 不卡av一区二区| 麻豆精品一区二区综合av| 国产精品中文字幕亚洲欧美 | 成人国产综合| 国产午夜精品一区二区三区欧美| 亚洲va久久| 久久免费大视频| 国产精品.xx视频.xxtv| 欧美a在线观看| 久久激情五月婷婷| 蜜臀久久久久久久| 亚洲福利专区| 成人在线视频区| 午夜天堂精品久久久久| 欧美日韩尤物久久| 精品久久电影| 国产亚洲一区| 久久久久99| 日韩在线欧美| 成人国产精品一区二区免费麻豆| 国产欧美一区二区三区国产幕精品| 免播放器亚洲| 国产亚洲福利| 不卡中文一二三区| 国产三级一区| 欧美视频久久| 国产欧美日韩一区二区三区四区| 亚洲精品婷婷| 久久av在线| 国产精品三上| 欧美一区在线观看视频| 亚洲午夜国产成人| 欧美一级专区| 亚洲一区二区免费看| 国模 一区 二区 三区| 欧美三级第一页| 国产欧美亚洲一区| 国产精品网站在线看| 日本一区免费网站| 午夜国产精品视频| 欧美91视频| 麻豆成人91精品二区三区| 美女性感视频久久| 精品久久在线| 成人精品视频| 久久中文字幕一区二区| 亚洲1区在线| 少妇精品久久久| 亚洲不卡视频| 欧美日韩一区自拍| 你懂的国产精品永久在线| 今天的高清视频免费播放成人| 91久久午夜| 亚洲精品韩国| 日韩专区在线视频| 欧美日韩1区2区3区| 欧美激情91| 欧美日韩免费观看视频| 亚洲综合电影| 美女精品在线观看| 欧美片网站免费| 国产精品调教视频| 亚洲精品国产嫩草在线观看 | 日韩中文字幕一区二区三区| 三上悠亚国产精品一区二区三区| 国产91在线播放精品| 国产在线|日韩| 国产亚洲在线观看| 日本午夜精品一区二区三区电影| 一区久久精品| 欧美日韩va| 日韩免费一区| 日韩在线观看一区二区| 婷婷精品在线观看| 在线国产一区| 国产精品qvod| 亚洲成人不卡| 免费看欧美美女黄的网站| 午夜性色一区二区三区免费视频| 亚洲一区中文| 亚洲成人精选| 欧美日韩精品一区二区三区在线观看| 免费日韩一区二区三区| 91看片一区| 在线看片福利| 深夜福利亚洲| 久久久久久一区二区| 9色国产精品| 国产精品极品在线观看| 激情婷婷亚洲| 亚欧洲精品视频在线观看| 日本在线啊啊| 亚州av一区| 久久婷婷一区| 日韩一二三区在线观看| 久久国产精品久久w女人spa| 国产日韩中文在线中文字幕| 日韩专区精品| 日韩av中文字幕一区二区| 欧美一区91| 精品国产不卡| 日韩精品中文字幕一区二区| 日韩精品看片| 麻豆精品在线视频| 免费日韩av| 国产亚洲一区二区三区啪| 人人精品久久| 亚洲黄页一区| 日韩成人a**站| 欧美一级久久| 精品美女视频 | 欧美日韩1区| 亚洲欧美不卡| 亚洲精品成人图区| 国产精品自在| 无码日韩精品一区二区免费| 99国产精品久久久久久久| 免费欧美一区| 国产不卡一区| 神马午夜久久| 美女网站久久| 7777精品| 久久国产直播| 日韩毛片视频| 亚洲免费网址| 国产亚洲精品精品国产亚洲综合| 麻豆91精品视频| 亚洲二区视频| 国产亚洲一区| 国产91一区| 久久国产视频网| 欧美在线网站| 精品视频网站| 99国产精品视频免费观看一公开| 国产探花一区二区| 久久国产中文字幕| 欧美日韩18| 日韩精品一区二区三区免费观看| 特黄毛片在线观看| 亚洲一区二区三区久久久| 欧美激情在线精品一区二区三区| 亚洲v在线看| 国产欧美精品久久| 99精品99| 久久精品xxxxx| 国产毛片一区| 国产成人精品免费视| 色狠狠一区二区三区| 超碰超碰人人人人精品| 亚洲精品乱码久久久久久蜜桃麻豆 | 最近国产精品视频| 久久九九电影| 久久不卡日韩美女| 亚洲精品黄色| 伊人影院久久| 色一区二区三区| 国产精品s色| 亚洲精一区二区三区| 亚洲欧美日韩高清在线| 麻豆视频久久| 日韩高清一区二区| 99国产一区| av资源亚洲| 国产欧美日韩影院| 丝袜诱惑制服诱惑色一区在线观看| 欧美亚洲自偷自偷| 午夜视频精品| 欧美日韩在线网站| 精品久久一区| 亚洲精品麻豆| 性色av一区二区怡红| 久久人人97超碰国产公开结果| 久久精品av麻豆的观看方式| 热久久免费视频| 亚洲不卡av不卡一区二区| 大香伊人久久精品一区二区 | 激情偷拍久久| 亚洲午夜久久久久久尤物|