Tomcat分析五 —— Connector分析

​ Connector用于接收请求并将请求封装成Request和Response具体处理,底层使用Socket进行连接,Request和Response是按照HTTP协议来封装的,所以Connector同时实现了TCP/IP协议和HTTP协议。

​ Request和Response封装完后交给Container进行处理,Container就是Servlet的容器,Container处理完返回给Connector,最后Connector使用Socket将处理结果返回给客户端,整个请求就处理结束。

5.1 Connector的结构

​ Connector中具体是用ProtocolHandler处理请求的,不同的ProtocolHandler代表不同的连接类型。

​ Http11Protocol使用普通Socket连接,Http11NioProtocol使用NioSocket连接的

​ ProtocolHandler有三个重要组件:Endpoint、Processor和Adapter。

Endpoint 处理底层Socket的网络连接 —— 实现TCP/IP协议

Process 将Endpoint接收到的Socket封装成Request —— 实现HTTP协议

Adapter 用于将封装好的Request交给Container进行具体处理 —— 将请求适配到Servlet容器进行处理

Endpoint的抽象实现AbstractEndpoint里面定义的Acceptor和AsyncTimeout两个内部类和一个Handler接口

​ Acceptor 用于监听请求

​ AsyncTimeout 检查异步request的超时

​ Handler 处理接收到的Socket,在内部调用Process进行处理
在这里插入图片描述

5.2 Connector自身类

​ Connector类的作用是为了在它创建时 创建ProtocolHandler,然后在生命周期的相关方法中调用了ProtocolHandler的相关生命周期方法。

​ Connector的使用方法是通过Connector标签配置在conf/server.xml文件中,所以Connector是在Catalina的load方法中根据conf/server.xml配置文件创建Server对象时创建的。Connector的生命周期方法是在Service中调用的。

###Connector的创建

​ Connector的创建过程主要是初始化ProtocolHandler。根据server.xml配置的Connector的protocol属性,会设置到Connector构造函数的参数中,用于指定ProtocolHandler的类型。

​ 根据protocol参数指定protocolHandlerClassName,根据反射实例化ProtocolHandler并赋值给当前的protocolHandler属性

public Connector(String protocol) {
    setProtocol(protocol);
    try {
        Class<?> clazz = Class.forName(protocolHandlerClassName);
        this.protocolHandler = (ProtocolHandler) clazz.getDeclaredConstructor().newInstance();
    } catch (Exception e) {
    }
}

​ setProtocol方法设置了protocolHandlerClassName属性

​ APr是Apache Protable Runtime的缩写,是Apache提供的一个运行时环境,使用它需要安装,Tomcat可以自己检测出来,并使用apr里面的协议。

​ 没有安装apr,会根据配置的HTTP/1.1属性将protocolHandlerClassName设置为org.apache.coyote.http11.Http11Protocol

tomcat8 默认使用 org.apache.coyote.http11.Http11NioProtocol
public void setProtocol(String protocol) {
    if (AprLifecycleListener.isAprAvailable()) {
        if ("HTTP/1.1".equals(protocol)) {
            setProtocolHandlerClassName
            ("org.apache.coyote.http11.Http11AprProtocol");
        } else if ("AJP/1.3".equals(protocol)) {
            setProtocolHandlerClassName
            ("org.apache.coyote.ajp.AjpAprProtocol");
        } else if (protocol != null) {
            setProtocolHandlerClassName(protocol);
        } else {
            setProtocolHandlerClassName
            ("org.apache.coyote.http11.Http11AprProtocol");
        }
    } else {
        if ("HTTP/1.1".equals(protocol)) {
            setProtocolHandlerClassName
            ("org.apache.coyote.http11.Http11Protocol");
        } else if ("AJP/1.3".equals(protocol)) {
            setProtocolHandlerClassName
            ("org.apache.coyote.ajp.AjpProtocol");
        } else if (protocol != null) {
            setProtocolHandlerClassName(protocol);
        }
    }
}

Connector生命周期处理方法

​ 主要调用了ProtocolHandler的相应生命周期方法

public class Connector extends LifecycleMBeanBase
  
protected void initInternal() throws LifecycleException {
    super.initInternal();
  	//新建adapter,并设置到protocolHandler
    adapter = new CoyoteAdapter(this);
    protocolHandler.setAdapter(adapter);
    if( null == parseBodyMethodsSet ) {
        setParseBodyMethods(getParseBodyMethods());
    }
    try {
        protocolHandler.init();
    } catch (Exception e) {
    }
    // 初始化Initialize mapper listener
    mapperListener.init();
}

protected void startInternal() throws LifecycleException {
  //判断端口小于0抛出异常
   if (getPort() < 0) {
            throw new LifecycleException(sm.getString(
                    "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
        }
  setState(LifecycleState.STARTING);
  	try {
    protocolHandler.start();
  } catch (Exception e) {
  }
  mapperListener.start();
}

 protected void stopInternal() throws LifecycleException {
        setState(LifecycleState.STOPPING);
        try {
            protocolHandler.stop();
        } catch (Exception e) {
        }
        mapperListener.stop();
    }

protected void destroyInternal() throws LifecycleException {
  		//调用MapperListener的destory方法
        mapperListener.destroy();
        try {
          //调用protocolHandler的destory方法
            protocolHandler.destroy();
        } catch (Exception e) {
        }
        if (getService() != null) {
           //将当前的Connector从service中删除
            getService().removeConnector(this);
        }
  		 //调用父类的destoryInternel方法
        super.destroyInternal();
    }

##5.3 ProtocolHandler

​ Tomcat的ProtocolHandler的继承结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9XctNelk-1587140773094)(images/image-20200417101242718.png)]
​ ProtocolHandler有一个抽象实现类AbstractProtocol,下面分了两类

1. AbstractAjpProtocol	又分为AjpApr、AjpNio和Ajp协议
2. AbstractHTTP11Protocol 分为AbstractHttp11jsse(Http11Nio和Http11)、Http11Apr

​ Http11Nio的构造函数中创建了NioEndpoint类型的Endpoint,并新建了Http11ConnectionHandler类型的Handler然后设置到了Endpoint

public class Http11NioProtocol extends AbstractHttp11JsseProtocol<NioChannel> {
    public Http11NioProtocol() {
        endpoint=new NioEndpoint();
        cHandler = new Http11ConnectionHandler(this);
        ((NioEndpoint) endpoint).setHandler(cHandler);
        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
        setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
    }

​ 四个生命周期方法是在父类AbstractProtocol中实现的,主要调用了Endpoing的生命周期方法。

5.4 处理TPC/IP协议的Endpoint

​ Endpoint用于处理具体连接和传输数据,NioEndpoint继承子AbstractEndpoing,在NioEndpoint中新增了Poller和SocketProcessor内部类

​ NioEndpoint的init和start方法在父类AbstractEndpoint中

public abstract class AbstractEndpoint<S> {
public void init() throws Exception {
    if (this.bindOnInit) {
        this.bind();
        this.bindState = AbstractEndpoint.BindState.BOUND_ON_INIT;
    }
}
public final void start() throws Exception {
    if (this.bindState == AbstractEndpoint.BindState.UNBOUND) {
        this.bind();
        this.bindState = AbstractEndpoint.BindState.BOUND_ON_START;
    }
    this.startInternal();
}

​ 这两个方法主要调用bind和startInternal方法,他们是模版方法,在NioEndpoint中实现

​ acceptor用于接收请求,然后交给poller处理

public class NioEndpoint extends AbstractEndpoint<NioChannel> {

public void bind() throws Exception {
    serverSock = ServerSocketChannel.open();
    socketProperties.setProperties(serverSock.socket());
    InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
    serverSock.socket().bind(addr,getBacklog());
    serverSock.configureBlocking(true); //mimic APR behavior
    serverSock.socket().setSoTimeout(getSocketProperties().getSoTimeout());
		//	初始化需要启动accrptor线程的个数,为0则改为1,否则不能工作
    // Initialize thread count defaults for acceptor, poller
    if (acceptorThreadCount == 0) {
        // FIXME: Doesn't seem to work that well with multiple accept threads
        acceptorThreadCount = 1;
    }
  	// 初始化需要启动poller的线程个数,<=0 改为1
    if (pollerThreadCount <= 0) {
        //minimum one poller thread
        pollerThreadCount = 1;
    }
    stopLatch = new CountDownLatch(pollerThreadCount);
    // Initialize SSL if needed 是否需要初始化SSL
    if (isSSLEnabled()) {
        SSLUtil sslUtil = handler.getSslImplementation().getSSLUtil(this);

        sslContext = sslUtil.createSSLContext();
        sslContext.init(wrap(sslUtil.getKeyManagers()),
                sslUtil.getTrustManagers(), null);

        SSLSessionContext sessionContext =
            sslContext.getServerSessionContext();
        if (sessionContext != null) {
            sslUtil.configureSessionContext(sessionContext);
        }
        // Determine which cipher suites and protocols to enable
        enabledCiphers = sslUtil.getEnableableCiphers(sslContext);
        enabledProtocols = sslUtil.getEnableableProtocols(sslContext);
    }

    if (oomParachute>0) reclaimParachute(true);
    selectorPool.open();
}

  public void startInternal() throws Exception {
        if (!running) {
            running = true;
            paused = false;
            // Create worker collection 创建Executor
            if ( getExecutor() == null ) {
                createExecutor();
            }
            initializeConnectionLatch();
            // Start poller threads 启动poller线程
            pollers = new Poller[getPollerThreadCount()];
            for (int i=0; i<pollers.length; i++) {
                pollers[i] = new Poller();
                Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                pollerThread.setPriority(threadPriority);
                pollerThread.setDaemon(true);
                pollerThread.start();
            }
           //启动acceptor线程
            startAcceptorThreads();
        }
    }

​ startAcceptorThreads方法,getAcceptorThreadCount()是获取的init方法中处理过的acceptorThreadCount属性,然后启动相应数量的Acceptor线程来接收请求。

protected final void startAcceptorThreads() {
    int count = getAcceptorThreadCount();
    acceptors = new Acceptor[count];
    for (int i = 0; i < count; i++) {
        acceptors[i] = createAcceptor();
        String threadName = getName() + "-Acceptor-" + i;
        acceptors[i].setThreadName(threadName);
        Thread t = new Thread(acceptors[i], threadName);
        t.setPriority(getAcceptorThreadPriority());
        t.setDaemon(getDaemon());
        t.start();
    }
}

5.5 处理HTTP协议的Processor

​ Processor用于处理应用层协议(如HTTP),有两个AbstractProcessor抽象类,分别在coyote包和upgrade包。(左边和右边),右边是Servlet3.1后新增的,用于处理HTTP的升级协议。

​ 如http升级WebSocket协议,当正常的Processor处理后如果Socket状态是UPGRADING,那么Endpoint中的Handler将会接着创建并调用upgrade包中的processor进行处理。

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qOF5CAUD-1587140773097)(images/image-20200417104222859.png)]

​ coyote包中的Processor和前面的ProtocolHandler对应,具体实现层协议处理请求的是AbstractAjpProcess和AbstractHttp11Processor中的process方法,这个方法首先封装了Request和Response,然后调用Adapter将请求传递到了Container中,最后对处理的结果进行处理,如有没有启动异步处理、处理过程中有没有抛出异常。

5.6 适配器Adapter

​ Adapter只有一个实现类,就是connector包下的CoyoteAdapter类。

​ Processor在process方法中会调用Adapter的sevice方法处理请求

​ Adapter的service方法主要调用Container管道中的invoke方法处理请求

​ 处理前对Request和Response做了处理,将原来创建的coyote包下的Request和Response封装成connector的Request和Response,并在处理完成后判断是否启动了Comet(长连接模式)和是否启动了异步模式,并作出相应处理。

​ 调用Container管道的相应代码

public class CoyoteAdapter implements Adapter {
public void service(org.apache.coyote.Request req,
                    org.apache.coyote.Response res)
    throws Exception {

    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);

    if (request == null) {

        // Create objects
        request = connector.createRequest();
        request.setCoyoteRequest(req);
        response = connector.createResponse();
        response.setCoyoteResponse(res);

        // Link objects
        request.setResponse(response);
        response.setRequest(request);

        // Set as notes
        req.setNote(ADAPTER_NOTES, request);
        res.setNote(ADAPTER_NOTES, response);

        // Set query string encoding
        req.getParameters().setQueryStringEncoding
            (connector.getURIEncoding());
              req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
            postParseSuccess = postParseRequest(req, request, res, response);
            if (postParseSuccess) {
                //check valves if we support async
                request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
                // Calling the container
                connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);

​ 这里首先从Connector中获取Service(Connector在initInternal方法中创建CoyoteAdapter时将自己设置到了CoyoteAdapter中),

​ 然后Service中获取Container,接着获取管道的第一个Value,最后调用invoke方法执行请求。

​ Service中保存的是最顶层的容器,当调用最顶层容器管道的invoke方法时,管道将逐层调用各层容器管道中的Value的invoke方法,知道最后调用Wrapper的管道中的BaseValue(StandardWrapperValve)来处理Filter和Servlet。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值