Tomcat Connector组件的初始化

Tomcat Connector组件的初始化


前言

Connector组件是Tomcat两大核心组件之一,其主要负责监听服务器指定端口的请求,解析请求报文为Request对象与Response对象。后将Request与Response传递至Container组件进行后续处理。


一、Connector组件整体结构

Connector运行基本流程如下所示。Endpoint负责监听请求,并将Socket传递至Processor。Processor对Socket中的请求报文进行解析,封装出Tomcat Request与Tomcat Response对象。Adaptor将获取到到的Tomcat Request与Tomcat Response对象进行进一步的解析,获得Servlet Request与Servlet Response,后继续向Container组件传递。
在这里插入图片描述

二、Connector组件的初始化

1.构造方法

在Connector类的构造方法中使用反射构造出Protocol实例(默认使用org.apache.coyote.http11.Http11NioProtocol类)。经类型转换后将ProtocolHandle对象的引用赋值给Connector对象的protocolHandle属性。

public Connector(String protocol) {
        setProtocol(protocol);
        // Instantiate protocol handler
        ProtocolHandler p = null;
        try {
            Class<?> clazz = Class.forName(protocolHandlerClassName);
            p = (ProtocolHandler) clazz.getConstructor().newInstance();
        } catch (Exception e) {
            log.error(sm.getString(
                    "coyoteConnector.protocolHandlerInstantiationFailed"), e);
        } finally {
            this.protocolHandler = p;
        }

        if (Globals.STRICT_SERVLET_COMPLIANCE) {
            uriCharset = StandardCharsets.ISO_8859_1;
        } else {
            uriCharset = StandardCharsets.UTF_8;
        }

        // Default for Connector depends on this (deprecated) system property
        if (Boolean.parseBoolean(System.getProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "false"))) {
            encodedSolidusHandling = EncodedSolidusHandling.DECODE;
        }
    }

在Http11NioProtocol的构造函数中调用了父类的构造函数,为Http11NioProtocol的endPoint属性赋值。我们可以一直追溯下去,直到AbstractHttp11Protocol类,我们可以看到AbstractHttp11Protocol的构造函数在调用了父类的构造函数后还为EndPoint类创建了Handle实例的引用。

   public Http11NioProtocol() {
        super(new NioEndpoint());
    }
    public AbstractHttp11Protocol(AbstractEndpoint<S> endpoint) {
        super(endpoint);
        setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
        //创建Handle实例
        ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
        setHandler(cHandler);
        //为endpoint设置handle引用
        getEndpoint().setHandler(cHandler);
    }

2.初始化触发

Connector组件的初始化操作,由StandardService的initInternal()调用connector.init()触发:

    @Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();

        if (engine != null) {
            engine.init();
        }

        // Initialize any Executors
        for (Executor executor : findExecutors()) {
            if (executor instanceof JmxEnabled) {
                ((JmxEnabled) executor).setDomain(getDomain());
            }
            executor.init();
        }

        // Initialize mapper listener
        mapperListener.init();

        // Initialize our defined Connectors
        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                try {
                	//触发Connector进行初始化操作
                    connector.init();
                } catch (Exception e) {
                    String message = sm.getString(
                            "standardService.connector.initFailed", connector);
                    log.error(message, e);

                    if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
                        throw new LifecycleException(message);
                }
            }
        }
    }

3.Connector的initInternal方法

由于Connector类继承了LifecycleBase抽象类,故connector.init()其实是调用了从LifecycleBase继承来的init()方法。
在init()方法内部,LifecycleBase又通过调用各个实现类 各自实现的initInternal()方法,来完成各个组件的定制化的初始化过程。

在这里插入图片描述

public final synchronized void init() throws LifecycleException {
      if (!state.equals(LifecycleState.NEW)) {
          invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
      }

      try {
          setStateInternal(LifecycleState.INITIALIZING, null, false);
          //在connector初始化过程中,这里会调用Connector的initInternal()方法
          initInternal();
          setStateInternal(LifecycleState.INITIALIZED, null, false);
      } catch (Throwable t) {
          handleSubClassException(t, "lifecycleBase.initFail", toString());
      }
}
protected void initInternal() throws LifecycleException {

        super.initInternal();

        // 初始化Adapter组件
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);

        // Make sure parseBodyMethodsSet has a default
        if (null == parseBodyMethodsSet) {
            setParseBodyMethods(getParseBodyMethods());
        }

        if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) {
            throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
                    getProtocolHandlerClassName()));
        }
        if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
            throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
                    getProtocolHandlerClassName()));
        }
        if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
                protocolHandler instanceof AbstractHttp11JsseProtocol) {
            AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
                    (AbstractHttp11JsseProtocol<?>) protocolHandler;
            if (jsseProtocolHandler.isSSLEnabled() &&
                    jsseProtocolHandler.getSslImplementationName() == null) {
                // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
                jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
            }
        }

        try {
        	//初始化protocolHandle组件
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }
  }

4.protocolHandler.init()

protocolHandler.init()主要调用了AbstractProtocol抽象类的init()方法,其主要是用于触发endpoint的初始化方法
在这里插入图片描述

 public void init() throws Exception {
        if (getLog().isInfoEnabled()) {
            getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
        }

        if (oname == null) {
            // Component not pre-registered so register it
            oname = createObjectName();
            if (oname != null) {
                Registry.getRegistry(null, null).registerComponent(this, oname, null);
            }
        }

        if (this.domain != null) {
            ObjectName rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
            this.rgOname = rgOname;
            Registry.getRegistry(null, null).registerComponent(
                    getHandler().getGlobal(), rgOname, null);
        }

        String endpointName = getName();
        endpoint.setName(endpointName.substring(1, endpointName.length()-1));
        endpoint.setDomain(domain);
        
		//调用endpoint的初始化方法
        endpoint.init();
    }

5.endpoint.bind()

endpoint.init()由NioEndpoint从AbstractEndpoint抽象类继承而来,该方法内部主要调用了AbstractEndpoint中的抽象方法bind(),bind()方法的具体实现由具体的实现类进行复写。
在此处默认由NioEndpoint类实现对bind()方法的复写。
在这里插入图片描述

public void bind() throws Exception {

        if (!getUseInheritedChannel()) {
        	//绑定要监听的端口地址 如:0.0.0.0/0.0.0.0:8080
            serverSock = ServerSocketChannel.open();
            socketProperties.setProperties(serverSock.socket());
            InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
            serverSock.socket().bind(addr,getAcceptCount());
        } else {
            // Retrieve the channel provided by the OS
            Channel ic = System.inheritedChannel();
            if (ic instanceof ServerSocketChannel) {
                serverSock = (ServerSocketChannel) ic;
            }
            if (serverSock == null) {
                throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
            }
        }
        serverSock.configureBlocking(true); //mimic APR behavior

        // Initialize thread count defaults for acceptor, poller
        if (acceptorThreadCount == 0) {
            // FIXME: Doesn't seem to work that well with multiple accept threads
            acceptorThreadCount = 1;
        }
        if (pollerThreadCount <= 0) {
            //minimum one poller thread
            pollerThreadCount = 1;
        }
        setStopLatch(new CountDownLatch(pollerThreadCount));

        // Initialize SSL if needed
        initialiseSsl();

        selectorPool.open();
 }

参考文献

链接: tomcat之Connector的结构.
链接: Tomcat8源码分析系列-启动分析(二) Catalina初始化.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值