• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Java > Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解

Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解

作者:draculav 字体:[增加 减小] 来源:互联网 时间:2017-05-28

draculav 通过本文主要向大家介绍了Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

 StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程中,它的start:   

// Start our child containers, if any
  Container children[] = findChildren();
  List<Future<Void>> results = new ArrayList<>();
  for (int i = 0; i < children.length; i++) {
   results.add(startStopExecutor.submit(new StartChild(children[i])));
  }
  boolean fail = false;
  for (Future<Void> result : results) {
   try {
    result.get();
   } catch (Exception e) {
    log.error(sm.getString("containerBase.threadedStartFailed"), e);
    fail = true;
   }
  }
  if (fail) {
   throw new LifecycleException(
     sm.getString("containerBase.threadedStartFailed"));
  }
</div>
 private static class StartChild implements Callable<Void> {
  private Container child;
  public StartChild(Container child) {
   this.child = child;
  }
  @Override
  public Void call() throws LifecycleException {
   child.start();
   return null;
  }
 }
</div>

  这个start流程中,initInternal方法是ContainerBase的代码,还是那个初始化startStopExecutor的,线程名例如Thread[localhost-startStop-1,5,main],这次是用来初始化host的子容器的,然后是StandardHost中的startInternal方法,主要是注册了一个errorValue,如果现有的pipeline中没有errorvalue,则反射创建org.apache.catalina.valves.ErrorReportValve实例,并加入pipeline中,容器pipeline加入Value时会发布一个Container.ADD_VALVE_EVENT事件,与engine一样,之后进入ContainerBase的startInternal,但是这次Realm是null不需要启动,然后findChildren出StandardEngine[Tomcat]. StandardHost [localhost].StandardContext[],然后同样新开个线程new StartChild,start同样是上面的代码,需要特别说明的是,这次before_init的事件有监听的了,FixContextListener,DisablePersistSessionListener,MemoryLeakTrackingListener;FixContextListener监听的处理,会加入一个用于不做用户身份认证的安全检查的Value:               

Context context = (Context) event.getLifecycle();
    if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
     context.setConfigured(true);
    }
    // LoginConfig is required to process @ServletSecurity
    // annotations
    if (context.getLoginConfig() == null) {
     context.setLoginConfig(
       new LoginConfig("NONE", null, null, null));
     context.getPipeline().addValve(new NonLoginAuthenticator());
    }
</div>

   DisablePersistSessionListener监听只处理start事件,所以这里只判断了一下发现不是就出去了,其实这里可以思考下,有没有更好的办法,让监听不只是广播方式,能不能用订阅方式,先不细想了,接着看代码,MemoryLeakTrackingListener只监听了after_start事件,这步同样什么都没做。

  于是来到了StandardContext的initInternal,它的super.initInternal又是一个startStopExecutor,ContainerBase的super.initInternal就不再说了,发送j2ee.object.created消息:         

Notification notification = new Notification("j2ee.object.created",
     this.getObjectName(), sequenceNumber.getAndIncrement());
   broadcaster.sendNotification(notification);
</div>

   Notification是EventObject的子类,代表由MBean发出的通知,MBean server发出的通知会包含发出的MBean的引用,如果MBean注册了监听,可以通过object name或引用获取消息发出者,官方建议使用object name;sendNotification方法:

 /**
  * Sends a notification.
  *
  * If an {@code Executor} was specified in the constructor, it will be given one
  * task per selected listener to deliver the notification to that listener.
  *
  * @param notification The notification to send.
  */
 public void sendNotification(Notification notification) {
  if (notification == null) {
   return;
  }
  boolean enabled;
  for (ListenerInfo li : listenerList) {
   try {
    enabled = li.filter == null ||
     li.filter.isNotificationEnabled(notification);
   } catch (Exception e) {
    if (logger.debugOn()) {
     logger.debug("sendNotification", e);
    }
    continue;
   }
   if (enabled) {
    executor.execute(new SendNotifJob(notification, li));
   }
  }
 }
</div>

  发完消息就转变状态为初始化完成,因为监听器是注册在context容器上的,于是after_init事件又触发了那三个监听器,这一阶段监听器什么都没处理走了下过场而已;before_start同走过场;然后StandardContext的startInternal方法,发布了个j2ee.state.starting消息object name为Tomcat:j2eeType=WebModule,name=//localhost/,J2EEApplication=none, J2EEServer=none;setConfigured(false)还没有正确的配置;设置WebResourceRoot,WebResourceRoot提供整个应用资源处理类的各种方法,内嵌用的实现类是StandardRoot,set的过程中加了写锁:        

try {
    setResources(new StandardRoot(this));
   } catch (IllegalArgumentException e) {
    log.error(sm.getString("standardContext.resourcesInit"), e);
    ok = false;
   }
</div>

   StandardRoot的属性allResources:

private final List<List<WebResourceSet>> allResources =
   new ArrayList<>();
 {
  allResources.add(preResources);
  allResources.add(mainResources);
  allResources.add(classResources);
  allResources.add(jarResources);
  allResources.add(postResources);
 }
</div>

  http://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/WebResourceRoot.html有相关说明,我就不翻译了。

  set之后就是启动resourcesStart,initInternal执行的是StandardRoot的initInternal方法,super.initInternal中依然是那两行代码,register(cache, getObjectNameKeyProperties() + ",name=Cache")会发送MBeanServerNotification. REGISTRATION_NOTIFICATION通知,生成ObjectName这里cacheJmxName是Tomcat:type=WebResourceRoot,host=localhost,context=/,name=Cache;registerURLStreamHandlerFactory里面的代码是TomcatURLStreamHandlerFactory.register()这行代码的注释说这是为了支持war包内的jar资源的。之后是循环上面的allResources,init里面加入的webResourceSet,但是由于全都是空的,所以等于没执行,就不说了,回头再仔细看看什么情况下回不为空,还是内嵌的就是空的。createMainResourceSet主要是设置个主目录,例如/tmp/tomcat-docbase.3031819619941848514.80,然后是各种资源该放在哪个子目录的一些设置代码;这次资源有一个了,所以可以有一个start了,DirResourceSet的;super.initInternal()的super是AbstractFileResourceSet:

 //-------------------------------------------------------- Lifecycle methods
 @Override
 protected void initInternal() throws LifecycleException {
  super.initInternal();
  // Is this an exploded web application?
  if (getWebAppMount().equals("")) {
   // Look for a manifest
   File mf = file("META-INF/MANIFEST.MF", true);
   if (mf != null && mf.isFile()) {
    try (FileInputStream fis = new FileInputStream(mf)) {
     setManifest(new Manifest(fis));
    } catch (IOException e) {
     log.warn(sm.getString("dirResourceSet.manifestFail", mf.getAbsolutePath()), e);
    }
   }
  }
 }
</div>

  super.initInternal主要是对base目录进行了一些规范化处理,规范的方法主要是UnixFileSystem中的canonicalize其中还使用ExpiringCache对路径做了缓存,另外还有在normalize方法中对路径中类似"\.."的部分做了处理。WebAppMount是Web应用发布资源的位置,必须以‘/'开头,这里应该是通过它来判断不是war包部署的模式,然后由于manifest没找到,所以方法返回初始化完成,这个资源一路状态变化就启动完了。

  回到StandardRoot,接下来是processWebInfLib方法,代

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

相关文章

  • 2017-05-28详解Java反射实现Aop代理
  • 2017-05-28CentOS安装solr 4.10.3详细教程
  • 2017-05-28详解springboot整合mongodb
  • 2017-05-28超实用的Java快捷键(总结)
  • 2017-05-28Java中final,finally,finalize三个关键字的区别_动力节点Java学院整理
  • 2017-05-28spring boot日志管理配置
  • 2017-09-13java中Collection对象的使用
  • 2017-05-28Java内存各部分OOM出现原因及解决方法(必看)
  • 2017-05-28java多线程编程技术详解和实例代码
  • 2017-05-28Java 8 lambda初试示例详解

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • java服务端微信APP支付接口详解
    • 简单实现Java验证码功能
    • 详解在Spring Boot中使用Mysql和JPA
    • 详解JAVA的封装
    • 基于Java的正则表达式
    • Java 常用类解析:java异常机制,异常栈,异常处理方式,异常链,异常丢失详解
    • java算法导论之FloydWarshall算法实现代码
    • 详解常用的Spring Bean扩展接口
    • Java 归并排序算法、堆排序算法实例详解
    • java 算法之快速排序实现代码

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有