激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|

服務器之家 - 編程語言 - JAVA教程 - Spring Boot啟動過程(五)之Springboot內嵌Tomcat對象的start教程詳解

Spring Boot啟動過程(五)之Springboot內嵌Tomcat對象的start教程詳解

2020-09-16 15:30draculav JAVA教程

這篇文章主要介紹了Spring Boot啟動過程(五)之Springboot內嵌Tomcat對象的start的相關資料,需要的朋友可以參考下

  標題和Spring Boot啟動過程(四)之Spring Boot內嵌Tomcat啟動很像,所以特別強調一下,這個是Tomcat對象的。

  從TomcatEmbeddedServletContainer的this.tomcat.start()開始,主要是利用LifecycleBase對這一套容器(engine,host,context及wrapper)進行啟動并發布諸如configure_start、before_init、after_start的lifecycleEvent事件給相應的監聽器(如果有的話)。進入start,因為此時狀態是LifecycleState.NEW,所以會執行init方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public final synchronized void init() throws LifecycleException {
 if(!this.state.equals(LifecycleState.NEW)) {
  this.invalidTransition("before_init");
 }
 try {
  this.setStateInternal(LifecycleState.INITIALIZING, (Object)null, false);
  this.initInternal();
  this.setStateInternal(LifecycleState.INITIALIZED, (Object)null, false);
 } catch (Throwable var2) {
  ExceptionUtils.handleThrowable(var2);
  this.setStateInternal(LifecycleState.FAILED, (Object)null, false);
  throw new LifecycleException(sm.getString("lifecycleBase.initFail", new Object[]{this.toString()}), var2);
 }
}

   首先,狀態變為LifecycleState.INITIALIZING并發布一個before_init的LifecycleEvent給所有lifecycleListeners:

  這里的super:

  因為上面是server.start調用的start方法,所以雖然方法的代碼在LifecycleBase中,但this指的是StandardServer的實例,于是這里的this.initInternal走的是StandardServer的initInternal方法,initInternal首先調用了super.initInternal,這里的super是LifecycleMBeanBase,MBean是用于JMX的能代表管理資源的管理構件,JMX定義了四種管理構件:標準、動態、開放和模型管理構件。每一種管理構件可以根據不同的環境需要進行制定,檢查標準管理構件接口和應用設計模式的過程被稱為內省(Introspection),動態管理構件提供了更大的靈活性,它可以在運行期暴露自己的管理接口。它的實現是通過實現一個特定的接口DynamicMBean。MBeanFactoryInitializer初始化是在BackgroundPreinitializer的onApplicationEvent。MBean功能相當強大,例如可以提供服務器的遠程管理,當然也可以自定義此類功能: 

  onameStringCache = register(new StringCache(), "type=StringCache")注冊全局字符串緩存,這里是使用DynamicMBean的方式,注冊后StringCache也提供了類似上圖的被管理功能,可以遠程清楚服務器的字符串緩存等。 下一句globalNamingResources.init()同樣的LifecycleBase的init套路,先是setStateInternal更新globalNamingResources的LifecycleState狀態為INITIALIZING發布before_init事件,然后NamingResourcesImpl的initInternal,里面依然是之前的super.initInternal(),顯示注冊ContextResource、ContextEnvironment、ContextResourceLink避免注冊時序問題,重復注冊沒關系;又是一個globalNamingResources的LifecycleBase的setStateInternal方法,更新LifecycleState狀態為INITIALIZED發布after_init事件;然后回到StandardServer的initInternal,循環init之前add給server的service:

  又是的LifecycleBase的init,只不過這次是StandardService[Tomcat],更新的LifecycleState狀態為INITIALIZING發布before_init事件,StandardService的initInternal,super之后是engine.init,同樣engine現在也是初始化階段,更新狀態發布事件,然后進入StandardEngine的initInternal:

?
1
2
3
4
5
6
protected void initInternal() throws LifecycleException {
 // Ensure that a Realm is present before any attempt is made to start
 // one. This will create the default NullRealm if necessary.
 getRealm();
 super.initInternal();
}

  Realm是關于權限的,具體可以看http://tomcat.apache.org/tomcat-8.0-doc/realm-howto.html;super(ContainerBase).initInternal創建了一個線程池startStopExecutor,這個startStopExecutor之后會接受兩種任務StartChild和StopChild用池線程啟動和停止子容器,StartStopThreadFactory會在創建線程時將線程設為守護線程,線程名例如:Thread [Tomcat(此處是容器的name)-startStop-1,5,main]。之后setStateInternal更新engine的LifecycleState狀態為INITIALIZED發布after_init事件。如果service之前add過Executor,會將這些Executor初始化,如果Executor是JmxEnabled則設置作用范圍。mapperListener的初始化沒有特殊邏輯,就是先改狀態為正在初始化并發布初始化之前的事件,然后注冊MBeanServer,再改狀態為初始化完成并發布初始化后事件。然后是在同步代碼塊中初始化Connector,不過之前已經將Connector與Service解綁了,所以這里什么都沒做。于是,Service的初始化完成了,更新service的LifecycleState狀態為INITIALIZED發布after_init事件。接著Server的初始化也完成了,同樣也是更新狀態發布事件。回到Server的start(雖然代碼在Lifecycle中),setStateInternal(LifecycleState.STARTING_PREP, null, false)更新LifecycleState狀態為準備啟動,發布before_start事件;startInternal首先發布一個configure_start事件,接著setState(LifecycleState.STARTING)就將狀態改為了STARTING同時發布start事件;globalNamingResources.start()更新狀態setStateInternal(LifecycleState.STARTING_PREP, null, false)發布before_start事件;globalNamingResources的startInternal方法,發布configure_start事件并setState(LifecycleState.STARTING),globalNamingResources啟動完成改狀態STARTED發布after_start事件;然后回到server代碼中,在同步代碼塊中啟動service:

?
1
2
3
4
5
6
// Start our defined Services
 synchronized (servicesLock) {
  for (int i = 0; i < services.length; i++) {
   services[i].start();
  }
 }

  當前狀態的Service會執行setStateInternal(LifecycleState.STARTING_PREP, null, false),然后到StandardService的startInternal方法,setState(LifecycleState.STARTING)不說了,接著是同步代碼塊中engine.start(),里面是engine狀態變更setStateInternal(LifecycleState.STARTING_PREP, null, false),startInternal中super.startInternal執行ContainerBase的對應方法,初始化logger;然后((Lifecycle) realm).start(),start方法里又是一個循環,從NEW到INITIALIZING的狀態變化,然后進入RealmBase的initInternal方法

 super.initInternal中MBeanServer,然后this.containerLog = container.getLogger(),此處container是StandardEngine[Tomcat],x509UsernameRetriever = createUsernameRetriever(x509UsernameRetrieverClassName),參考:https://bz.apache.org/bugzilla/show_bug.cgi?id=52500;狀態連續更新到INITIALIZED然后STARTING_PREP,發布的什么事件我就不寫了,現在還在Realm[Simple]中,接著是RealmBase的startInternal方法,它初始化了credentialHandler = new MessageDigestCredentialHandler()并將狀態由改為了STARTING發布start事件,接著又改狀態了STARTED事件after_start;然后回到了StandardEngine [Tomcat]中,通過ContainerBase的findChildren方法找到了子容器:

  隨后將host的啟動,提交給了之前初始化的startStopExecutor:

?
1
2
3
for (int i = 0; i < children.length; i++) {
  results.add(startStopExecutor.submit(new StartChild(children[i])));
 }

  借助Future<Void>獲取線程執行的返回值;

  下面就到了執行注冊到engine的pipeline中的Value對象了((Lifecycle) pipeline).start(),StandardPipeline整套的狀態變化事件發布我就不寫了,initInternal方法是空實現,需要說的只有pipeline的startInternal方法,會取第一個Value對象,如果沒有會執行basic(StandardEngineValve[Tomcat]實例),最后會將pipeline中的Value對象依次start:    

?
1
2
3
4
5
6
7
8
9
Valve current = first;
 if (current == null) {
  current = basic;
 }
 while (current != null) {
  if (current instanceof Lifecycle)
   ((Lifecycle) current).start();
  current = current.getNext();
 }

  StandardEngineValve的整套start不說了,其中initInternal只有super.initInternal的MBeanServer和初始化containerLog,startInternal就只有改變狀態也不說了,出來后是pipeline的狀態變化,這個方法狀態都是變為STARTING標配也沒啥好說的,STARTED然后回到engine,StandardEngine[Tomcat]變狀態為STARTING,之后是threadStart(),代碼在ContainerBase中,啟動了背景線程:

  上面configureEngine中配置的engine.setBackgroundProcessorDelay(this.backgroundProcessorDelay)指定背景線程的執行間隔Thread.sleep((long) ContainerBase.this. backgroundProcessorDelay * 1000L),背景線程會處理例如StandardContext中e.getLoginConfig() == null時e.getPipeline().addValve(new NonLoginAuthenticator()),這個value包含session管理的相關邏輯,例如背景線程會在每隔多長時間后判斷session是否失效之類。終于StandardEngine實例也到了STARTED狀態,該回到StandardService中了,前面說了我這并木有executor,所以沒執行:

?
1
2
3
4
5
synchronized (executors) {
  for (Executor executor: executors) {
   executor.start();
  }
 }

   然后是start前面初始化過的mapperListener:     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
setState(LifecycleState.STARTING);
 Engine engine = service.getContainer();
 if (engine == null) {
  return;
 }
 findDefaultHost();
 addListeners(engine);
 Container[] conHosts = engine.findChildren();
 for (Container conHost : conHosts) {
  Host host = (Host) conHost;
  if (!LifecycleState.NEW.equals(host.getState())) {
   // Registering the host will register the context and wrappers
   registerHost(host);
  }
 }

  上面代碼中給出的engine就是StandardEngine[Tomcat],findDefaultHost名字說的很清楚,我這里找出了localhost并set給MapperListener的mapper( mapper. setDefaultHostName ),addListeners本身是個遞歸,會將this(MapperListener)add給各個child容器(比如

?
1
2
3
4
5
6
StandardContext、StandardWrapper[default]和StandardWrapper[dispatcherServlet]):
  container.addContainerListener(this);
  container.addLifecycleListener(this);
  for (Container child : container.findChildren()) {
   addListeners(child);
  }

  雖然是遞歸,但是只有一棵樹,所以返回的是children中的根child也就是StandardEngine[Tomcat].StandardHost[localhost],registerHost(host)這里的host就是這個根child,registerHost主要是處理映射關系包括別名和通配符并記錄(mapper.addHost(host.getName(), aliases, host)),然后處理它的子容器registerContext,及子容器的子容器wrapper并將各級子容器路徑關聯起來:        

?
1
2
boolean jspWildCard = (wrapperName.equals("jsp") && mapping.endsWith("/*"));
   wrappers.add(new WrapperMappingInfo(mapping, wrapper, jspWildCard, resourceOnly));

  注冊的這些用于匹配請求的路徑;然后同步代碼塊中啟動連接同前面一樣,這里什么因為解除綁定了所以都沒做。

  于是TomcatEmbeddedServletContainer中的這個Tomcat對象的start就完成了,至于其中Context等子容器的Start因為不在一個線程里所以決定單獨寫一篇。

==========================================================

咱最近用的github:https://github.com/saaavsaaa

以上所述是小編給大家介紹的Spring Boot啟動過程(五)之Springboot內嵌Tomcat對象的start教程詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:http://www.cnblogs.com/saaav/p/6544374.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲国产午夜精品 | 国产91对白叫床清晰播放 | 免费观看高清视频网站 | 欧美成人一区二区视频 | 看免费5xxaaa毛片 | 毛片免费观看日本中文 | 夜夜夜影院 | 精品久久久久久久 | 久久久成人一区二区免费影院 | 久草经典视频 | 久久96国产精品久久久 | 精品一区二区久久久久久久网精 | 成人精品久久 | 日韩视频一区 | 嗯哈~不行好大h双性 | 看毛片电影 | 亚洲骚妻 | 激情综合视频 | 日本a级一区 | 成年免费网站 | av免费在线播放网址 | 久久不射电影 | 色综合视频网 | 亚洲午夜天堂吃瓜在线 | 毛片视频大全 | 99视频网| 免费观看视频网站 | 91精品国产91热久久久做人人 | 91久久91久久精品免观看 | 深夜福利视频免费观看 | 18被视频免费观看视频 | 日本久久网站 | 国产精品久久久久久久久久了 | 欧美a视频在线观看 | 99精品电影 | 特片网久久 | 欧美一级网站 | 特大黑人videos与另类娇小 | 水卜樱一区二区av | 国产交换3p国产精品 | 一级大片在线观看 |