查漏补缺:连接器在Tomcat中是如何设计的

2021-02-23    分类: 网站建设

从连接器(Connector)源码说起

既然是来解析连接器(Connector),那么我们直接从源码入手,后面所有源码我会剔除不重要部分,所以会忽略大部分源码细节,只关注流程。源码如下(高能预警,大量代码):

  1. public class Connector extends LifecycleMBeanBase { 
  2.  public Connector() { 
  3.  this("org.apache.coyote.http11.Http11NioProtocol"); 
  4.  } 
  5.  public Connector(String protocol) { 
  6.  boolean aprConnector = AprLifecycleListener.isAprAvailable() && 
  7.  AprLifecycleListener.getUseAprConnector(); 
  8.  if ("HTTP/1.1".equals(protocol) || protocol == null) { 
  9.  if (aprConnector) { 
  10.  protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol"; 
  11.  } else { 
  12.  protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol"; 
  13.  } 
  14.  } else if ("AJP/1.3".equals(protocol)) { 
  15.  if (aprConnector) { 
  16.  protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol"; 
  17.  } else { 
  18.  protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol"; 
  19.  } 
  20.  } else { 
  21.  protocolHandlerClassName = protocol; 
  22.  } 
  23.  // Instantiate protocol handler 
  24.  ProtocolHandler p = null; 
  25.  try { 
  26.  Class clazz = Class.forName(protocolHandlerClassName); 
  27.  p = (ProtocolHandler) clazz.getConstructor().newInstance(); 
  28.  } catch (Exception e) { 
  29.  log.error(sm.getString( 
  30.  "coyoteConnector.protocolHandlerInstantiationFailed"), e); 
  31.  } finally { 
  32.  this.protocolHandler = p; 
  33.  } 
  34.  // Default for Connector depends on this system property 
  35.  setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")); 
  36.  } 

我们来看看Connector的构造方法,其实只做了一件事情,就是根据协议设置对应的ProtocolHandler,根据名称我们知道,这是协议处理类,所以连接器内部的一个重要子模块就是ProtocolHandler。

关于生命周期

我们看到Connector继承了LifecycleMBeanBase,我们来看看Connector的最终继承关系:

金九银十,查漏补缺:连接器在Tomcat中是如何设计的

我们看到最终实现的是Lifecycle接口,我们看看这个接口是何方神圣。我把其接口的注释拿下来解释下

  1. /** 
  2.  * Common interface for component life cycle methods. Catalina components 
  3.  * may implement this interface (as well as the appropriate interface(s) for 
  4.  * the functionality they support) in order to provide a consistent mechanism 
  5.  * to start and stop the component. 
  6.  * start() 
  7.  * ----------------------------- 
  8.  * | | 
  9.  * | init() | 
  10.  * NEW -»-- INITIALIZING | 
  11.  * | | | | ------------------«----------------------- 
  12.  * | | |auto | | | 
  13.  * | | \|/ start() \|/ \|/ auto auto stop() | 
  14.  * | | INITIALIZED --»-- STARTING_PREP --»- STARTING --»- STARTED --»--- | 
  15.  * | | | | | 
  16.  * | |destroy()| | | 
  17.  * | --»-----«-- ------------------------«-------------------------------- ^ 
  18.  * | | | | 
  19.  * | | \|/ auto auto start() | 
  20.  * | | STOPPING_PREP ----»---- STOPPING ------»----- STOPPED -----»----- 
  21.  * | \|/ ^ | ^ 
  22.  * | | stop() | | | 
  23.  * | | -------------------------- | | 
  24.  * | | | | | 
  25.  * | | | destroy() destroy() | | 
  26.  * | | FAILED ----»------ DESTROYING ---«----------------- | 
  27.  * | | ^ | | 
  28.  * | | destroy() | |auto | 
  29.  * | --------»----------------- \|/ | 
  30.  * | DESTROYED | 
  31.  * | | 
  32.  * | stop() | 
  33.  * ----»-----------------------------»------------------------------ 
  34.  * 
  35.  * Any state can transition to FAILED. 
  36.  * 
  37.  * Calling start() while a component is in states STARTING_PREP, STARTING or 
  38.  * STARTED has no effect. 
  39.  * 
  40.  * Calling start() while a component is in state NEW will cause init() to be 
  41.  * called immediately after the start() method is entered. 
  42.  * 
  43.  * Calling stop() while a component is in states STOPPING_PREP, STOPPING or 
  44.  * STOPPED has no effect. 
  45.  * 
  46.  * Calling stop() while a component is in state NEW transitions the component 
  47.  * to STOPPED. This is typically encountered when a component fails to start and 
  48.  * does not start all its sub-components. When the component is stopped, it will 
  49.  * try to stop all sub-components - even those it didn't start. 
  50.  * 
  51.  * Attempting any other transition will throw {@link LifecycleException}. 
  52.  * 
  53.  *  
  54.  * The {@link LifecycleEvent}s fired during state changes are defined in the 
  55.  * methods that trigger the changed. No {@link LifecycleEvent}s are fired if the 
  56.  * attempted transition is not valid. 
  57. 这段注释翻译就是,这个接口是提供给组件声明周期管理的,并且提供了声明周期流转图。这里我们只需要知道正常流程即可:

    1. New--->Init()---->Start()---->Stop()--->Destory() 

    从生命周期探索连接器

    根据上面的生命周期说明,我们可以知道连接器(Connector)就是按照如此的声明周期管理的,所以我们找到了线索,所以连接器肯定会先初始化然后再启动。我们查看其initInternal()方法可以知道连接器初始化做了什么事情,源码如下:

    1. @Override 
    2.  protected void initInternal() throws LifecycleException { 
    3.  super.initInternal(); 
    4.  if (protocolHandler == null) { 
    5.  throw new LifecycleException( 
    6.  sm.getString("coyoteConnector.protocolHandlerInstantiationFailed")); 
    7.  } 
    8.  // Initialize adapter 
    9.  adapter = new CoyoteAdapter(this); 
    10.  protocolHandler.setAdapter(adapter); 
    11.  if (service != null) { 
    12.  protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor()); 
    13.  } 
    14.  // Make sure parseBodyMethodsSet has a default 
    15.  if (null == parseBodyMethodsSet) { 
    16.  setParseBodyMethods(getParseBodyMethods()); 
    17.  } 
    18.  if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) { 
    19.  throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener", 
    20.  getProtocolHandlerClassName())); 
    21.  } 
    22.  if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) { 
    23.  throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary", 
    24.  getProtocolHandlerClassName())); 
    25.  } 
    26.  if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUSEOpenssl() && 
    27.  protocolHandler instanceof AbstractHttp11JsseProtocol) { 
    28.  AbstractHttp11JsseProtocol jsseProtocolHandler = 
    29.  (AbstractHttp11JsseProtocol) protocolHandler; 
    30.  if (jsseProtocolHandler.issslEnabled() && 
    31.  jsseProtocolHandler.getsslImplementationName() == null) { 
    32.  // Openssl is compatible with the JSSE configuration, so use it if APR is available 
    33.  jsseProtocolHandler.setsslImplementationName(OpensslImplementation.class.getName()); 
    34.  } 
    35.  } 
    36.  try { 
    37.  protocolHandler.init(); 
    38.  } catch (Exception e) { 
    39.  throw new LifecycleException( 
    40.  sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e); 
    41.  } 
    42.  } 

    根据上面源码,我们发现主要是处理protocolHandler并初始化它,同时我们注意到了protocolHandler 设置了一个适配器,我们看看这个适配器是做啥的,跟踪源码如下:

    1. /** 
    2.  * The adapter, used to call the connector. 
    3.  * 
    4.  *&nbs

      本文名称:查漏补缺:连接器在Tomcat中是如何设计的
      链接分享:https://www.cdcxhl.com/news/102494.html

      成都网站建设公司_创新互联,为您提供网页设计公司网站营销微信公众号品牌网站建设网站制作ChatGPT

      广告

      声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

    搜索引擎优化