欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Boot启动过程(五)之Springboot内嵌Tomcat对象的start教程详解

程序员文章站 2024-02-29 13:41:04
  标题和spring boot启动过程(四)之spring boot内嵌tomcat启动很像,所以特别强调一下,这个是tomcat对象的。   从tomcatembed...

  标题和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方法:

 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:

 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:

 // 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),参考:;状态连续更新到initialized然后starting_prep,发布的什么事件我就不写了,现在还在realm[simple]中,接着是realmbase的startinternal方法,它初始化了credentialhandler = new messagedigestcredentialhandler()并将状态由改为了starting发布start事件,接着又改状态了started事件after_start;然后回到了standardengine [tomcat]中,通过containerbase的findchildren方法找到了子容器:

  随后将host的启动,提交给了之前初始化的startstopexecutor:

 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:    

 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,所以没执行:

 synchronized (executors) {
   for (executor executor: executors) {
    executor.start();
   }
  }

   然后是start前面初始化过的mapperlistener:     

 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容器(比如

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并将各级子容器路径关联起来:        

boolean jspwildcard = (wrappername.equals("jsp") && mapping.endswith("/*"));
   wrappers.add(new wrappermappinginfo(mapping, wrapper, jspwildcard, resourceonly));

  注册的这些用于匹配请求的路径;然后同步代码块中启动连接同前面一样,这里什么因为解除绑定了所以都没做。

  于是tomcatembeddedservletcontainer中的这个tomcat对象的start就完成了,至于其中context等子容器的start因为不在一个线程里所以决定单独写一篇。

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

咱最近用的github:

以上所述是小编给大家介绍的spring boot启动过程(五)之springboot内嵌tomcat对象的start教程详解,希望对大家有所帮助