Tomcat启动过程连接部分-(下)

Tomcat是怎样初始化socket连接及怎样接受socket连接:

    前面一篇有讲到StandardService的start还有两部分,因为这两部分都与Socket连接相关,所以放到下篇:

  一、     mapperListener.start();

        

可以看到其也有Lifecycle接口,所以直接看其startInternal方法:

public void startInternal() throws LifecycleException {
    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);
        }
    }
}

这里的findDefaultHost方法就是将StandardEngine的defaultHost设置到这个MapperListener类的Mapper对象中:

private void findDefaultHost() {
    Engine engine = service.getContainer();
    String defaultHost = engine.getDefaultHost();
    ..........
    if (found) {
        mapper.setDefaultHostName(defaultHost);
    } 
    ............
}

对应的就是server.xml配置文件中的这里:

                         

    然后addListeners(engine)方法:

private void addListeners(Container container) {
    container.addContainerListener(this);
    container.addLifecycleListener(this);
    for (Container child : container.findChildren()) {
        addListeners(child);
    }
}

这里的最开始的容器是StandardEngine,然后findChildren,所以这里会一直往下往下设置,Engine->Host->Context->Wrapper。

再然后就是下面的registerHost(host)方法:

private void registerHost(Host host) {
            ...........
            registerContext((Context) container);
           .........
}
private void registerContext(Context context) {
    String contextPath = context.getPath();
    .......
    Host host = (Host)context.getParent();

    WebResourceRoot resources = context.getResources();
    String[] welcomeFiles = context.findWelcomeFiles();
    List<WrapperMappingInfo> wrappers = new ArrayList<>();
       ..........
        prepareWrapperMappingInfo(context, (Wrapper) container, wrappers);
       ..........
       mapper.addContextVersion(host.getName(), host, contextPath,
            context.getWebappVersion(), context, welcomeFiles, resources,
            wrappers);
}

这个还会调prepareWrapperMappingInfo方法。关于mapperListener.start()的这个关键逻辑就是在这里,这里要处理的内容就是将Engine、Host、context、wrapper(用于查到对应Servlet映射处理类)容器的内容设置到MapperListener类中,关键的是设置到其成员变量Mapper类中:

  Mapper类中有些属性值:

   

  同时关键的地方要知道,MapperListener是StandardService的成员变量:

     

并且StandardService也有一个Mapper类的成员变量:

                                       

再来看下其的构造方法:

public MapperListener(Service service) {
    this.service = service;
    this.mapper = service.getMapper();
}

所以这个MapperListener类的Mapper最终也是有赋值到StandardService的Mapper。

 

   二、Connector的start ,Connector也有实现Lifecycle接口,所以看其startInternal方法:

@Override
protected void startInternal() throws LifecycleException {
       .......
    setState(LifecycleState.STARTING);
    try {
        protocolHandler.start();
       ........
}

前面有提到这里的连接器是Http11NioProtocol:

                            

可以看到其基础实现是AbstractProtocol:

   看其的start方法:

public void start() throws Exception {
    ..........
    endpoint.start();

    // Start async timeout thread
    asyncTimeout = new AsyncTimeout();
    Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
    int priority = endpoint.getThreadPriority();
    if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
        priority = Thread.NORM_PRIORITY;
    }
    timeoutThread.setPriority(priority);
    timeoutThread.setDaemon(true);
    timeoutThread.start();
}

 

这个endpoint就是NioEndpoint,看其startInternal方法:

    

@Override
public void startInternal() throws Exception {
        ..........
        // Create worker collection
        if ( getExecutor() == null ) {
            createExecutor();
        }

        // Start poller threads
        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();
        }

        startAcceptorThreads();
        ...........
}

public Poller() throws IOException { this.selector = Selector.open(); } 

一、  先看createExecutor方法(我们并没有在server.xml配置,所以为空):

public void createExecutor() {
    internalExecutor = true;
    TaskQueue taskqueue = new TaskQueue();
    TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
    executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
    taskqueue.setParent( (ThreadPoolExecutor) executor);
}

   可以看到这里的执行器是一个线程池,其中生产线程的工厂是TaskThreadFactory,现在看下TaskThreadFactory是生产一个怎样的线程:

@Override
public Thread newThread(Runnable r) {
    TaskThread t = new TaskThread(group, r, namePrefix + threadNumber.getAndIncrement());
    t.setDaemon(daemon);
    t.setPriority(threadPriority);
     ........
    return t;
}

可以看到其是将一个Runnable接口变为TaskThread线程对象。

   二、现在看下Poller类(轮询器),其是NioEndpoint的内部类:

        

其实现了Runable接口,看其run接口:

@Override
public void run() {
          ..........
                hasEvents = events();
                if (wakeupCounter.getAndSet(-1) > 0) {
                    keyCount = selector.selectNow();
                } else {
                    keyCount = selector.select(selectorTimeout);
                }
            }
            ...........
        //either we timed out o we woke up, process events first
        if ( keyCount == 0 ) hasEvents = (hasEvents | events());

        Iterator<SelectionKey> iterator =
            keyCount > 0 ? selector.selectedKeys().iterator() : null;
        while (iterator != null && iterator.hasNext()) {
            SelectionKey sk = iterator.next();
            NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
            // Attachment may be null if another thread has called
            // cancelledKey()
            if (attachment == null) {
                iterator.remove();
            } else {
                iterator.remove();
                processKey(sk, attachment);
            }
          ..........
}

   看下event方法: 

private final SynchronizedQueue<PollerEvent> events =
        new SynchronizedQueue<>();
public boolean events() {
    boolean result = false;
    PollerEvent pe = null;
    for (int i = 0, size = events.size(); i < size && (pe = events.poll()) != null; i++ ) {
        result = true;
        try {
            pe.run();
            pe.reset();
           ..........
    }

    return result;
}
                               


其run方法:

@Override
public void run() {
    if (interestOps == OP_REGISTER) {
        try {
            socket.getIOChannel().register(
                    socket.getPoller().getSelector(), SelectionKey.OP_READ, socketWrapper);
        } catch (Exception x) {
            log.error(sm.getString("endpoint.nio.registerFail"), x);
        }
    } else {
        final SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
        try {
            if (key == null) {
               
                socket.socketWrapper.getEndpoint().countDownConnection();
                ((NioSocketWrapper) socket.socketWrapper).closed = true;
            } else {
                final NioSocketWrapper socketWrapper = (NioSocketWrapper) key.attachment();
                if (socketWrapper != null) {
                    //we are registering the key to start with, reset the fairness counter.
                    int ops = key.interestOps() | interestOps;
                    socketWrapper.interestOps(ops);
                    key.interestOps(ops);
                }   
                  .............
    }
}

可以看到这里PollerEvent类实现Runnable接口,同时其有三个成员变量:NioChannel(可以简单看为是像ServerSocketChannel/SocketChannel之类的类)、interestOps(表面现在是那种时间、Nio的SelectionKey有四种状态)、NioSocketWrapper(与SelectKey绑定的,其实现SocketWrapperBase):

      

   这个方法,如果当前EventPoller的interestOps是OP_REGISTER,则将SocketChannel注册为SelectionKey.OP_READ。如果不是,则将Selector查询到的SelectionKey的interestOps同步到SocketWrapper,并将当前EventPoller的interestOps也同步到对应的SelectionKey中。所以这里的先后顺序是OP_REGISTER->OP_READ,我们主要关注OP_READ。

    我们再来看下这个socket.getIOChannel().register()方法:

public final SelectionKey register(Selector sel, int ops,
                                   Object att).....
{
         .........
        SelectionKey k = findKey(sel);
        if (k != null) {
            k.interestOps(ops);
            k.attach(att);
        }
       ........
}

这里可以知道socketWrapper(NioSocketWrapper),就是在这个时候与设置到SelectionKey的。

     那这里的events是在什么时候填充的?同时这里通过selector去轮询查询SelectKey,之后再看processKey(sk, attachment),这个processKey方法到后面讲,因为还缺一些东西,不好理解。

     EventPoller的的run方法结束。

     三、接着我们看startAcceptorThreads方法:

            

protected final void startAcceptorThreads() {
    int count = getAcceptorThreadCount();
    acceptors = new ArrayList<>(count);

    for (int i = 0; i < count; i++) {
        Acceptor<U> acceptor = new Acceptor<>(this);
        String threadName = getName() + "-Acceptor-" + i;
        acceptor.setThreadName(threadName);
        acceptors.add(acceptor);
        Thread t = new Thread(acceptor, threadName);
        t.setPriority(getAcceptorThreadPriority());
        t.setDaemon(getDaemon());
        t.start();
    }
}

  这个Acceptor(接收器,所以其应该是是接受Socket请求的),与前面Poller类似,看其run方法:

@Override
public void run() {       while (endpoint.isRunning()) {        .........
        state = AcceptorState.RUNNING;
              ..........
            U socket = null;
            ........
                socket = endpoint.serverSocketAccept();
                  ..........
            if (endpoint.isRunning() && !endpoint.isPaused()) {
                // setSocketOptions() will hand the socket off to
                // an appropriate processor if successful
                if (!endpoint.setSocketOptions(socket)) {
                    endpoint.closeSocket(socket);
                }
               .............
         }
    state = AcceptorState.ENDED;
}

      这里endpoint就是NioEndpoint,看下endpoint.serverSocketAccept():   

@Override
protected SocketChannel serverSocketAccept() throws Exception {
    return serverSock.accept();
}

这里的serverSocket就是ServerSocketChannel,所以就是这个NioEndPoint的内部类Acceptor来接受socket请求,然后再来看下

endpoint.setSocketOptions(socket)方法:

@Override
protected boolean setSocketOptions(SocketChannel socket) {
    // Process the connection
    try {
        //disable blocking, APR style, we are gonna be polling it
        socket.configureBlocking(false);
        Socket sock = socket.socket();
        socketProperties.setProperties(sock);

        NioChannel channel = nioChannels.pop();  //其一个先创建、缓存、到时候能反复利用的作用:     (SynchronizedStack<NioChannel> nioChannels)
        if (channel == null) {  
            SocketBufferHandler bufhandler = new SocketBufferHandler(.....);
            if (isSSLEnabled()) {     //加密例如Https使用
                channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
            } else {
                channel = new NioChannel(socket, bufhandler);   //可以知道这里有将这个Socket设置到这个                  NioChannel
            }
        } else {
            channel.setIOChannel(socket);
            channel.reset();
        }
        getPoller0().register(channel);
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        try {
            log.error("",t);
        } catch (Throwable tt) {
            ExceptionUtils.handleThrowable(tt);
        }
        // Tell to close the socket
        return false;
    }
    return true;
}

看下其 getPoller0().register(channel)方法: 

public void register(final NioChannel socket) {
    socket.setPoller(this);
    NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
    socket.setSocketWrapper(ka);
    ka.setPoller(this);
    ka.setReadTimeout(getConnectionTimeout());
    ka.setWriteTimeout(getConnectionTimeout());
    ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
    ka.setSecure(isSSLEnabled());
    PollerEvent r = eventCache.pop();
    ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
    if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
    else r.reset(socket,ka,OP_REGISTER);
    addEvent(r);
}

这里先是将NioChannel 设置到 NioSocketWrapper(就是接受到的socket、serverSocket.accept()),之后可以将这个NioSocketWrapper看做是接收到的那个SocketChannel 了。然后是PollerEvent r = eventCache.pop(),我们现在还没有添加所以是空,则 new PollerEvent(socket,ka,OP_REGISTER),这里就与前面那个OP_REGISTER->OP-READl联系起来了,如果有就是将这个EventPoller再设置一次, r.reset(socket,ka,OP_REGISTER):

public PollerEvent(NioChannel ch, NioSocketWrapper w, int intOps) {
    reset(ch, w, intOps);
}

public void reset(NioChannel ch, NioSocketWrapper w, int intOps) {
    socket = ch;
    interestOps = intOps;
    socketWrapper = w;
}

现在看下addEvent(r)方法(就是在这里将event添加到events的):

private void addEvent(PollerEvent event) {
    events.offer(event);
    if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
}

   这里就是将这个event添加到前面那个Poller类需要处理的events了,到这里两个实现Runnable接口的NioEndAppoint类的内部类Poller、Accptor,都已经通过:while (endpoint.isPaused() && endpoint.isRunning())、与while(true)在循环运行了。现在我们将这两个结合到一起来将前面的processKey(sk, attachment)方法:

      while (iterator != null && iterator.hasNext()) {
            SelectionKey sk = iterator.next();
            NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
            // Attachment may be null if another thread has called
            // cancelledKey()
            if (attachment == null) {
                iterator.remove();
            } else {
                iterator.remove();
                processKey(sk, attachment);
            }

这里通过Selector获取SelectionKey,然后通过SelectionKey获取NioSocketWrapper(即socketChanel)来调用processKey方法:

   所以这里整个的这个流程是:

      1、先在Accptor线程中通过serverSocketChannel.accpet去接收socketChannel,然后将这个SocketChannel转换为:EventPllor放放到队列events中。然后Poller线程获取到这个socketChannel,将其由OP_REGISTER,改为OP_READ可读的,之后再通过selector获取SocketionKey,再通过processKey方法处理这个SelectionKey:

protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
    ...........
    if (sk.isReadable() || sk.isWritable() ) {
        if ( attachment.getSendfileData() != null ) {
            processSendfile(sk,attachment, false);
        } else {
            unreg(sk, attachment, sk.readyOps());
            boolean closeSocket = false;
            // Read goes before write
            if (sk.isReadable()) {
                if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
                    closeSocket = true;
                }
            }
            if (!closeSocket && sk.isWritable()) {
                if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
                    closeSocket = true;
                }
            }
        .........
        }

             ,一般并不会调用attachment.getSendfileData(),所以应该是sk.isReadable(),再调用processSocket(attachment, SocketEvent.OPEN_READ, true):

   SynchronizedStack<SocketProcessorBase<S>> processorCache   

public boolean processSocket(SocketWrapperBase<S> socketWrapper,
        SocketEvent event, boolean dispatch) {
         ........
        SocketProcessorBase<S> sc = processorCache.pop();
        if (sc == null) {
            sc = createSocketProcessor(socketWrapper, event);
        } else {
            sc.reset(socketWrapper, event);
        }
        Executor executor = getExecutor();
        if (dispatch && executor != null) {
            executor.execute(sc);
        } else {
            sc.run();
          ......
    return true;
}
这里的createSocketProcessor方法创建的是SocketProcessor

                                           

所以SocketProcessor也有实现Runnable接口:

     而这里的Executor executor = getExecutor()就是前面创建的ThreadPoolExecutor,其创建的线程对象是TaskThread:

    其run方法:  

@Override
public final void run() {
    synchronized (socketWrapper) {
        if (socketWrapper.isClosed()) {
            return;
        }
        doRun();
    }
}

  

@Override
    protected void doRun() {
        NioChannel socket = socketWrapper.getSocket();
        SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
                ............
                if (event == null) {
                    state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
                } else {
                    state = getHandler().process(socketWrapper, event);
                }
                ......
}

这里的getHandler是ConnectionHandler,其的初始化:

public AbstractHttp11Protocol(AbstractEndpoint<S,?> endpoint) {
    super(endpoint);
    setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
    ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
    setHandler(cHandler);
    getEndpoint().setHandler(cHandler);
}

process方法:

   

@Override
public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
       ............
    S socket = wrapper.getSocket();
           ..........
        if (processor == null) {
            processor = getProtocol().createProcessor();
            register(processor);
        }
          ........
        SocketState state = SocketState.CLOSED;
        do {
            state = processor.process(wrapper, status);

               ..........
}

 这里的getProtocol().createProcessor():

Override
protected Processor createProcessor() {
    Http11Processor processor = new Http11Processor(this, adapter);
    return processor;
}

注意现在的status是SocketEvent.OPEN_READ,之后是怎样处理的可以看下前面写的这篇文章。

自此整个tomcat整体的启动,以及接收请求过程大体结果已经梳理,启动、连接过程中其他的一些比较重要的细节之后再理解、梳理下。

 

  补充:

      1、我们请求一个servlet的url:

                               

             

                  2、之后其就通过executor去创建TaskThread线程去运行  :

                              

                   

                    

            

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值