# tomcat概述

# 什么是tomcat(百度百科)

  • 一个免费,开放源代码的web应用服务器,属于轻量级应用服务器
  • tomcat实际上是Apache服务器的扩展,但它是独立运行的
  • 一个servlet和jsp容器
  • 是 apache软件基金会Jakarta项目中的一个核心项目,由Apache、Sun和其它一些公司及个人共同开发而成

# 发展历程

  • Sun创建的第一个Servlet容器是JavaWebServer;Apache软件基金会同事创建了JServ,它是一个servlet引擎;
  • 1999年,Sun将JavaWebServer容器的源码贡献给Apache软件基金会,使得 JavaWebServer和 JServ合并为了Tomcat;

# 主要版本

  • Tomcat3.X,1999年对外发布;
  • Tomcat4.1,2002年9月;
  • tomcat5.0,2003年12月;
  • tomcat6.0,2007年2月;
  • tomcat7.0,2011年1月;
  • tomcat8.0,2014年6月;
  • tomcat9.0,2016年;

# tomcat设计--架构设计

tomcat架构

# connector(连接器,coyoto模块)

  • 连接器、协议、端点、io的关系

//连接器
public class Connector extends LifecycleMBeanBase  {
    /*xxx: 核心属性:协议处理器
     *  tomcat有一个默认的实现: coyoteProtocolHandler*/
    /*xxx: 它的作用在于: 对 协议 以及 I/O 进行抽象设计*/
    protected final ProtocolHandler protocolHandler;
}

/*xxx: 对不同的 协议 以及 I/O 方式 进行适配*/
    /*xxx: 提供了对协议的生命周期的模板方法: init,start,pause,resume,stop,destroy等*/
public interface ProtocolHandler {
    
}

public abstract class AbstractProtocol<S> implements ProtocolHandler,
        MBeanRegistration {
    /*xxx: 抽象端点*/
    /*xxx: 与之处于统一抽象层次的 处理器,由子类进行托管*/
    private final AbstractEndpoint<S,?> endpoint;
}

//协议本身,主要处理应用层面的一些参数
public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> {
    protected String getProtocolName() {
            return "Http";
    }
    private int maxHttpHeaderSize = 8 * 1024;
    //省略其他抽象...
}

//端点,io的载体
public abstract class AbstractEndpoint<S,U> {
}
public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel> {
}
  • NIO如何工作
/*xxx: NIO测试用例*/
public class NioStartTest {

    /*xxx: tomcat7及以下版本默认使用 bio, tomcat8及以上版本使用 nio*/
    /*xxx: bio,nio,aio的简单区别,来自网络: bio是一个连接一个线程(可能只是连接,不管有没有io操作),
       nio是一个请求一个线程(具有io请求的连接),
       aio是一个有效请求,一个线程(操作系统先把io请求操作完,再通知线程)*/
    public static void main(String[] args) throws IOException, InterruptedException {

        new Thread(new NioServer()).start();

        Thread.sleep(5000);
        System.out.println("服务端启动成功,启动客户端");

        new Thread(new NioClient()).start();
    }

    public static class NioServer implements Runnable{

        private Selector selector;

        private ServerSocketChannel acceptorChannel;

        private volatile boolean stop;

        public NioServer() throws IOException {
            //监听客户端连接
             acceptorChannel = ServerSocketChannel.open();
            //绑定监听端口
            acceptorChannel.bind(new InetSocketAddress(InetAddress.getByName("127.0.0.1"),8055));
            //并设置为非阻塞模式
            acceptorChannel.configureBlocking(false);
            //创建多路复用器,并启动线程
            selector= Selector.open();
            acceptorChannel.register(selector, SelectionKey.OP_ACCEPT);
        }

        public void stop(){
            this.stop = true;
        }

        @Override
        public void run() {
            while (!stop){
                try {
                    selector.select(1000);
                    Set selectedKeys = selector.selectedKeys();
                    Iterator iterator = selectedKeys.iterator();
                    SelectionKey key = null;

                    while (iterator.hasNext()){
                        key = (SelectionKey) iterator.next();
                        iterator.remove();
                        try {
                            //这里可以用线程池启线程去单独处理客户端的请求业务,核心在于此处
                            handleInput(key);
                        } catch (Exception e) {
                            if (key != null) {
                                key.cancel();
                                if (key.channel() != null)
                                    key.channel().close();
                            }
                        }
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        private void handleInput(SelectionKey key) throws IOException {

            if (key.isValid()) {
                //根据SelectionKey的操作位进行判断即可获知网络事件的类型,
                if (key.isAcceptable()) {
                    //通过ServerSocketChannel的accept接收客户端的连接请求并创建SocketChannel实例,
                    //完成上述操作后,相当于完成了TCP的三次握手,TCP物理链路正式建立。
                    //注意,我们需要将新创建的SocketChannel设置为异步非阻塞,同时也可以对其TCP参数进行设置,
                    //例如TCP接收和发送缓冲区的大小等,作为入门的例子,没有进行额外的参数设置。
                    ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                    /*xxx: 该方法是阻塞的*/
                    SocketChannel sc = ssc.accept();
                    sc.configureBlocking(false);
                    // Add the new connection to the selector
                    sc.register(selector, SelectionKey.OP_READ);
                }
                if (key.isReadable()) {
                    //首先创建一个ByteBuffer,由于我们事先无法得知客户端发送的码流大小,
                    //作为例程,我们开辟一个1M的缓冲区。然后调用SocketChannel的read方法读取请求码流。
                    //注意,由于我们已经将SocketChannel设置为异步非阻塞模式,因此它的read是非阻塞的。
                    //使用返回值进行判断,看读取到的字节数
                    SocketChannel sc = (SocketChannel) key.channel();
                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                    int readBytes = sc.read(readBuffer);
                    //返回值有以下三种可能的结果
                    //返回值大于0:读到了字节,对字节进行编解码;
                    //返回值等于0:没有读取到字节,属于正常场景,忽略;
                    //返回值为-1:链路已经关闭,需要关闭SocketChannel,释放资源。
                    if (readBytes > 0) {
                        //当读取到码流以后,我们进行解码,首先对readBuffer进行flip操作,
                        //它的作用是将缓冲区当前的limit设置为position,position设置为0,用于后续对缓冲区的读取操作。
                        //然后根据缓冲区可读的字节个数创建字节数组,
                        //调用ByteBuffer的get操作将缓冲区可读的字节数组复制到新创建的字节数组中,
                        //最后调用字符串的构造函数创建请求消息体并打印。
                        //如果请求指令是"QUERY TIME ORDER"则把服务器的当前时间编码后返回给客户端
                        readBuffer.flip();
                        byte[] bytes = new byte[readBuffer.remaining()];
                        readBuffer.get(bytes);
                        String body = new String(bytes, "UTF-8");
                        System.out.println("The server receive order : "
                                + body);
                        String currentTime = "QUERY TIME ORDER"
                                .equalsIgnoreCase(body) ? new java.util.Date(
                                System.currentTimeMillis()).toString()
                                : "BAD ORDER";
                        //异步发送应答消息给客户端
                        doWrite(sc, currentTime);
                    } else if (readBytes < 0) {
                        // 对端链路关闭
                        key.cancel();
                        sc.close();
                    } else
                        ; // 读到0字节,忽略
                }
            }
        }

        private void doWrite(SocketChannel channel, String response)
                throws IOException {
            //首先将字符串编码成字节数组,根据字节数组的容量创建ByteBuffer,
            //调用ByteBuffer的put操作将字节数组复制到缓冲区中,然后对缓冲区进行flip操作,
            //最后调用SocketChannel的write方法将缓冲区中的字节数组发送出去。
            //需要指出的是,由于SocketChannel是异步非阻塞的,它并不保证一次能够把需要发送的字节数组发送完,
            //此时会出现“写半包”问题,我们需要注册写操作,不断轮询Selector将没有发送完的ByteBuffer发送完毕,
            //可以通过ByteBuffer的hasRemain()方法判断消息是否发送完成。
            //此处仅仅是个简单的入门级例程,没有演示如何处理“写半包”场景。
            if (response != null && response.trim().length() > 0) {
                byte[] bytes = response.getBytes();
                ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
                writeBuffer.put(bytes);
                writeBuffer.flip();
                channel.write(writeBuffer);
            }
        }

    }

    public static class NioClient implements Runnable{

        private Selector selector;

        private SocketChannel socketChannel;

        private volatile boolean stop;

        public NioClient(){
            try {
                selector = Selector.open();
                socketChannel = SocketChannel.open();
                socketChannel.configureBlocking(false);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            try {
                //连接不成功,可以进行重连操作
                doConnect();
            } catch (IOException e) {
                e.printStackTrace();
            }

            while (!stop) {
                try {
                    //在循环体中轮询多路复用器Selector,当有就绪的Channel时,执行handleInput(key)方法
                    selector.select(1000);
                    Set selectedKeys = selector.selectedKeys();
                    Iterator it = selectedKeys.iterator();
                    SelectionKey key = null;
                    while (it.hasNext()) {
                        key = (SelectionKey) it.next();
                        it.remove();
                        try {
                            handleInput(key);
                        } catch (Exception e) {
                            if (key != null) {
                                key.cancel();
                                if (key.channel() != null)
                                    key.channel().close();
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(1);
                }
            }

            //线程退出循环后,我们需要对连接资源进行释放,以实现“优雅退出”.
            //由于多路复用器上可能注册成千上万的Channel或者pipe,如果一一对这些资源进行释放显然不合适。
            //因此,JDK底层会自动释放所有跟此多路复用器关联的资源。
            //多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册并关闭,所以不需要重复释放资源
            if (selector != null)
                try {
                    selector.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            System.out.println("客户端退出.");
        }

        private void handleInput(SelectionKey key) throws IOException {
            //我们首先对SelectionKey进行判断,看它处于什么状态。
            if (key.isValid()) {
                // 判断是否连接成功
                SocketChannel sc = (SocketChannel) key.channel();
                //如果是处于连接状态,说明服务端已经返回ACK应答消息。
                //这时我们需要对连接结果进行判断,调用SocketChannel的finishConnect()方法,
                //如果返回值为true,说明客户端连接成功;如果返回值为false或者直接抛出IOException,说明连接失败。
                //在本例程中,返回值为true,说明连接成功。
                if (key.isConnectable()) {
                    if (sc.finishConnect()) {
                        //将SocketChannel注册到多路复用器上,注册SelectionKey.OP_READ操作位,
                        //监听网络读操作,然后发送请求消息给服务端。
                        sc.register(selector, SelectionKey.OP_READ);
                        doWrite(sc);
                    } else
                        System.exit(1);// 连接失败,进程退出
                }
                //客户端是如何读取时间服务器应答消息的。
                if (key.isReadable()) {
                    //如果客户端接收到了服务端的应答消息,则SocketChannel是可读的,
                    //由于无法事先判断应答码流的大小,我们就预分配1M的接收缓冲区用于读取应答消息,
                    //调用SocketChannel的read()方法进行异步读取操作。由于是异步操作,所以必须对读取的结果进行判断。
                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                    int readBytes = sc.read(readBuffer);
                    if (readBytes > 0) {
                        //如果读取到了消息,则对消息进行解码,最后打印结果。执行完成后将stop置为true,线程退出循环。
                        readBuffer.flip();
                        byte[] bytes = new byte[readBuffer.remaining()];
                        readBuffer.get(bytes);
                        String body = new String(bytes, "UTF-8");
                        System.out.println("Now is : " + body);
                        this.stop = true;
                    } else if (readBytes < 0) {
                        // 对端链路关闭
                        key.cancel();
                        sc.close();
                    } else
                        ; // 读到0字节,忽略
                }
            }

        }

        //首先对SocketChannel的connect()操作进行判断,如果连接成功,
        //则将SocketChannel注册到多路复用器Selector上,注册SelectionKey.OP_READ,
        //如果没有直接连接成功,则说明服务端没有返回TCP握手应答消息,
        //但这并不代表连接失败,我们需要将SocketChannel注册到多路复用器Selector上,
        //注册SelectionKey.OP_CONNECT,当服务端返回TCP syn-ack消息后,
        //Selector就能够轮询到这个SocketChannel处于连接就绪状态。
        private void doConnect() throws IOException {
            // 如果直接连接成功,则注册到多路复用器上,发送请求消息,读应答
            if (socketChannel.connect(new InetSocketAddress("127.0.0.1", 8055))) {
                socketChannel.register(selector, SelectionKey.OP_READ);
                doWrite(socketChannel);
            } else {
                socketChannel.register(selector, SelectionKey.OP_CONNECT);
            }
        }

        //构造请求消息体,然后对其编码,写入到发送缓冲区中,最后调用SocketChannel的write方法进行发送。
        //由于发送是异步的,所以会存在“半包写”问题。最后通过hasRemaining()方法对发送结果进行判断,
        //如果缓冲区中的消息全部发送完成,打印"Send order 2 server succeed."
        private void doWrite(SocketChannel sc) throws IOException {
            byte[] req = "QUERY TIME ORDER".getBytes();
            ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);
            writeBuffer.put(req);
            writeBuffer.flip();
            sc.write(writeBuffer);
            if (!writeBuffer.hasRemaining())
                System.out.println("Send order 2 server succeed.");
        }
    }
}

  • NIO工作机制如何被启动
//package org.apache.catalina.core;
public class StandardService extends LifecycleMBeanBase implements Service {
    public void addConnector(Connector connector) {
        //省略其它抽象...
        try { 
           /*xxx: 在springBoot定制的start方法,会触发该 start条件*/
          if (getState().isAvailable()) {
              //该方法会开启相应的协议特性
              connector.start();
          }
             } catch (LifecycleException e) {
                 throw new IllegalArgumentException(
                         sm.getString("standardService.connector.startFailed", connector), e);
             }
        
             // Report this property change to interested listeners
        support.firePropertyChange("connector", null, connector);
    }

    //省略其它抽象...
}

/*xxx: 连接器,对应于协议,用于 处理协议*/
public class Connector extends LifecycleMBeanBase  {
    @Override
    protected void startInternal() throws LifecycleException {
        //省略其它抽象...
        setState(LifecycleState.STARTING);
        
        try {
            protocolHandler.start();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
        }
    }
    //省略其它抽象...
}

public abstract class AbstractProtocol<S> implements ProtocolHandler,
        MBeanRegistration {
    @Override
    public void start() throws Exception {
        //省略其它抽象...
        endpoint.start();
        //省略其它抽象...
    }
    //省略其它抽象...
}

public abstract class AbstractEndpoint<S,U> {
    //省略其它抽象...
    public final void start() throws Exception {
            if (bindState == BindState.UNBOUND) {
                //开启服务端监听
                bindWithCleanup();
                bindState = BindState.BOUND_ON_START;
            }
            startInternal();
    }

    private void bindWithCleanup() throws Exception {
            try {
                bind();
            } catch (Throwable t) {
                // Ensure open sockets etc. are cleaned up if something goes
                // wrong during bind
                ExceptionUtils.handleThrowable(t);
                unbind();
                throw t;
        }
    }
    //省略其它抽象...
}

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel> {
    /*xxx: nio的服务端 channel(本类) */
    private volatile ServerSocketChannel serverSock = null;
    /*xxx: 接收新的连接,并且将它们转为 工作线程 (父类)*/
    protected Acceptor<U> acceptor;
    /*xxx: 工作线程池(父类)*/
    private Executor executor = null;

    @Override
    public void bind() throws Exception {
        initServerSocket();
    
        setStopLatch(new CountDownLatch(1));
    
        // Initialize SSL if needed
        initialiseSsl();
    
        selectorPool.open(getName());
    }

    /*xxx:初始化时,会进行 创建服务端的 nio socketChannel*/
    protected void initServerSocket() throws Exception {
            if (!getUseInheritedChannel()) {
                serverSock = ServerSocketChannel.open();
                socketProperties.setProperties(serverSock.socket());
                InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
                /*xxx: accept队列的长度,该值作用于操作系统
                   当accept队列中连接的个数达到acceptCount时,队列满,进来的请求一律被拒绝。默认值是100*/
                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
    }
    //省略其它抽象...
}

//开启监听的流程
public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel> {
    private Poller poller = null;

    /*xxx: nio的服务端 channel(本类) */
    private volatile ServerSocketChannel serverSock = null;

    /*xxx: 接收新的连接,并且将它们转为 工作线程 (父类)*/
    protected Acceptor<U> acceptor;

    /*xxx: 工作线程池(父类)*/
    private Executor executor = null;

    @Override
    public void startInternal() throws Exception {
    
        if (!running) {
            running = true;
            paused = false;
    
            if (socketProperties.getProcessorCache() != 0) {
                processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getProcessorCache());
            }
            if (socketProperties.getEventCache() != 0) {
                eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getEventCache());
            }
            if (socketProperties.getBufferPool() != 0) {
                nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getBufferPool());
            }
    
            // Create worker collection
            //创建线程池
            if (getExecutor() == null) {
                createExecutor();
            }
    
            initializeConnectionLatch();
    
            // Start poller thread
            poller = new Poller();
            Thread pollerThread = new Thread(poller, getName() + "-ClientPoller");
            pollerThread.setPriority(threadPriority);
            pollerThread.setDaemon(true);
            pollerThread.start();
    
            startAcceptorThread();
        }
    }

     protected void startAcceptorThread() {
            acceptor = new Acceptor<>(this);
            String threadName = getName() + "-Acceptor";
            acceptor.setThreadName(threadName);
            Thread t = new Thread(acceptor, threadName);
            t.setPriority(getAcceptorThreadPriority());
            t.setDaemon(getDaemon());
            t.start();
     }

    /*xxx: 创建线程池,*/
    public void createExecutor() {
       internalExecutor = true;
       TaskQueue taskqueue = new TaskQueue();
       /*xxx: 工作线程池创建的线程名称,遵循: 协议名-exec-端口-线程号*/
       TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
       /*xxx: 创建工作线程池时,线程池最低保持了10个线程,最大可以达到参数设置的线程数,默认情况下是200 */
       executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
       taskqueue.setParent( (ThreadPoolExecutor) executor);
    }

    /*xxx: tomcat8处理 selector的核心封装方法 */
    public class Poller implements Runnable {
        private Selector selector;
        
        public Poller() throws IOException {
                    this.selector = Selector.open();
        }

        @Override
        /*xxx: 多路复用器,进行 客户端活跃线程的筛选 */
        public void run() {
            // Loop until destroy() is called
            while (true) {
                 boolean hasEvents = false;
                 try {
                    if (!close) {
                        hasEvents = events();
                        if (wakeupCounter.getAndSet(-1) > 0) {
                            // If we are here, means we have other stuff to do
                            // Do a non blocking select
                            keyCount = selector.selectNow();
                        } else {
                            keyCount = selector.select(selectorTimeout);
                        }
                        wakeupCounter.set(0);
                    }
                    if (close) {
                        events();
                        timeout(0, false);
                        try {
                            selector.close();
                        } catch (IOException ioe) {
                            log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
                        }
                        break;
                    }
                } catch (Throwable x) {
                    ExceptionUtils.handleThrowable(x);
                    log.error(sm.getString("endpoint.nio.selectorLoopError"), x);
                    continue;
                }
                // Either we timed out or we woke up, process events first
                if (keyCount == 0) {
                    hasEvents = (hasEvents | events());
                }
                 Iterator<SelectionKey> iterator =
                    keyCount > 0 ? selector.selectedKeys().iterator() : null;
                // Walk through the collection of ready keys and dispatch
                // any active event.
                /*xxx: 对客户端的事件进行处理 */
                while (iterator != null && iterator.hasNext()) {
                    SelectionKey sk = iterator.next();
                    NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
                    // Attachment may be null if another thread has called
                    // cancelledKey()
                    if (socketWrapper == null) {
                        iterator.remove();
                    } else {
                        iterator.remove();
                        processKey(sk, socketWrapper);
                    }
                }
                 // Process timeouts
                timeout(keyCount,hasEvents);
            }
             getStopLatch().countDown();
        }

        /*xxx: 处理客户端事件 */
        /*xxx: 在进行客户端处理时,多种情况下,都会触发 cancelKey方法,进而导致关闭有效的socket连接 */
        protected void processKey(SelectionKey sk, NioSocketWrapper socketWrapper) {
            try {
                /*xxx: 如果当前的poller已经关闭,则关闭当前的 socket连接 */
                if (close) {
                    cancelledKey(sk, socketWrapper);
                } else if (sk.isValid() && socketWrapper != null) {
                    if (sk.isReadable() || sk.isWritable()) {
                        if (socketWrapper.getSendfileData() != null) {
                            processSendfile(sk, socketWrapper, false);
                        } else {
                            unreg(sk, socketWrapper, sk.readyOps());
                            boolean closeSocket = false;
                            // Read goes before write
                            if (sk.isReadable()) {
                                if (socketWrapper.readOperation != null) {
                                    if (!socketWrapper.readOperation.process()) {
                                        closeSocket = true;
                                    }
                                    /*xxx: 处理客户端的 读取事件*/
                                } else if (!processSocket(socketWrapper, SocketEvent.OPEN_READ, true)) {
                                    closeSocket = true;
                                }
                            }
                            if (!closeSocket && sk.isWritable()) {
                                if (socketWrapper.writeOperation != null) {
                                    if (!socketWrapper.writeOperation.process()) {
                                        closeSocket = true;
                                    }
                                    /*xxx: 处理客户端的写入事件 */
                                } else if (!processSocket(socketWrapper, SocketEvent.OPEN_WRITE, true)) {
                                    closeSocket = true;
                                }
                            }
                            /*xxx: 如果读写失败,也需要关闭当前正在读写的 socket*/
                            if (closeSocket) {
                                cancelledKey(sk, socketWrapper);
                            }
                            /*xxx: 否则,socket保持为当前的长连接,继续参与下一次处理*/
                        }
                    }
                } else {
                    // Invalid key
                    /*xxx: 如果当前的 selectKey非法,也需要关闭 socket*/
                    cancelledKey(sk, socketWrapper);
                }
            } catch (CancelledKeyException ckx) {
                cancelledKey(sk, socketWrapper);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error(sm.getString("endpoint.nio.keyProcessingError"), t);
            }
        }
        //省略其它抽象...
    }

}

//package org.apache.tomcat.util.net;
public class Acceptor<U> implements Runnable {
    private final AbstractEndpoint<?,U> endpoint;

    public Acceptor(AbstractEndpoint<?,U> endpoint) {
            this.endpoint = endpoint;
    }

    @Override
    public void run() {
         int errorDelay = 0;
         try {
            // Loop until we receive a shutdown command
            while (!stopCalled) {
                 // Loop if endpoint is paused
                /*xxx: 当endpoint暂停时,就不从 os中获取 客户端socket连接,此时 客户端的 socket是阻塞的*/
                while (endpoint.isPaused() && !stopCalled) {
                    state = AcceptorState.PAUSED;
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }
                 if (stopCalled) {
                    break;
                }
                state = AcceptorState.RUNNING;
                 try {
                    //if we have reached max connections, wait
                    /*xxx: 增加endPoint的连接数,如果达到了最大连接数,则阻塞等待*/
                    /*xxx: 当 endpoint的连接数,小于 最大连接数时,才从队列中,获取socket连接*/
                    endpoint.countUpOrAwaitConnection();
                     // Endpoint might have been paused while waiting for latch
                    // If that is the case, don't accept new connections
                    if (endpoint.isPaused()) {
                        continue;
                    }
                     U socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = endpoint.serverSocketAccept();
                    } catch (Exception ioe) {
                        // We didn't get a socket
                        endpoint.countDownConnection();
                        if (endpoint.isRunning()) {
                            // Introduce delay if necessary
                            errorDelay = handleExceptionWithDelay(errorDelay);
                            // re-throw
                            throw ioe;
                        } else {
                            break;
                        }
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;
                     // Configure the socket
                    if (!stopCalled && !endpoint.isPaused()) {
                        // setSocketOptions() will hand the socket off to
                        // an appropriate processor if successful
                        /*xxx: 该方法会将 新的连接 与 selector进行关联*/
                        if (!endpoint.setSocketOptions(socket)) {
                            /*xxx: 如果于selector关联失败,则会释放当前有效的 socket连接 */
                            endpoint.closeSocket(socket);
                        }
                    } else {
                        endpoint.destroySocket(socket);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    String msg = sm.getString("endpoint.accept.fail");
                    // APR specific.
                    // Could push this down but not sure it is worth the trouble.
                    if (t instanceof Error) {
                        Error e = (Error) t;
                        if (e.getError() == 233) {
                            // Not an error on HP-UX so log as a warning
                            // so it can be filtered out on that platform
                            // See bug 50273
                            log.warn(msg, t);
                        } else {
                            log.error(msg, t);
                        }
                    } else {
                            log.error(msg, t);
                    }
                }
            }
        } finally {
            stopLatch.countDown();
        }
        state = AcceptorState.ENDED;
    }

}

//连接的保持
public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel> {
    /*xxx: 暂存所有与当前的socket相连的所有连接,通过 maxConnections 可以进行控制 */
    protected Map<U, SocketWrapperBase<S>> connections = new ConcurrentHashMap<>();

     @Override
     protected boolean setSocketOptions(SocketChannel socket) {
            NioSocketWrapper socketWrapper = null;
            try {
                // Allocate channel and wrapper
                NioChannel channel = null;
                if (nioChannels != null) {
                    channel = nioChannels.pop();
                }
                if (channel == null) {
                    SocketBufferHandler bufhandler = new SocketBufferHandler(
                            socketProperties.getAppReadBufSize(),
                            socketProperties.getAppWriteBufSize(),
                            socketProperties.getDirectBuffer());
                    if (isSSLEnabled()) {
                        channel = new SecureNioChannel(bufhandler, selectorPool, this);
                    } else {
                        channel = new NioChannel(bufhandler);
                    }
                }
                NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);
                channel.reset(socket, newWrapper);
                /*xxx: 将新建的连接进行保存,该变量保存了 tomcat任意时刻的活跃连接数 */
                connections.put(socket, newWrapper);
                socketWrapper = newWrapper;
    
                // Set socket properties
                // Disable blocking, polling will be used
                socket.configureBlocking(false);
                socketProperties.setProperties(socket.socket());
    
                socketWrapper.setReadTimeout(getConnectionTimeout());
                socketWrapper.setWriteTimeout(getConnectionTimeout());
                socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
                /*xxx: 将channel 与 selector 进行注册关联 */
                poller.register(channel, socketWrapper);
                return true;
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                try {
                    log.error(sm.getString("endpoint.socketOptionsError"), t);
                } catch (Throwable tt) {
                    ExceptionUtils.handleThrowable(tt);
                }
                if (socketWrapper == null) {
                    destroySocket(socket);
                }
            }
            // Tell to close the socket if needed
            return false;
     }
}
  • NIO在tomcat中如何工作

    • Poller线程充当Selector工作,完成客户端读写事件
    • Acceptor线程负责接收连接请求,连接请求完成,将客户连接缓存并与selector相关联
    • NioEndpoint充当ServerSocketChannel角色
  • 某次请求如何进入到容器中

public abstract class AbstractEndpoint<S,U> {
    
    /*xxx: 处理socket,实际上是处理 tcp协议与应用层协议的转换*/
    /*xxx: tcp 转换为 http */
    public boolean processSocket(SocketWrapperBase<S> socketWrapper,
                SocketEvent event, boolean dispatch) {
            try {
                if (socketWrapper == null) {
                    return false;
                }
                /*xxx: 并发请求时,可能有多个线程通过线程池同时运行并调度*/
                /*xxx: 这些线程共享,各自通过 SocketProcessor实例进行处理 */
                /*xxx: 这些不同的 SocketProcessor实例,共享同一个 handler*/
                /*xxx: 这些handler会被多个工作线程共享, 工作线程最少有10个,最大默认是200 */
                SocketProcessorBase<S> sc = null;
                if (processorCache != null) {
                    sc = processorCache.pop();
                }
                if (sc == null) {
                    sc = createSocketProcessor(socketWrapper, event);
                } else {
                    sc.reset(socketWrapper, event);
                }
                Executor executor = getExecutor();
                if (dispatch && executor != null) {
                    /*xxx: 通过线程池,响应客户端请求*/
                    executor.execute(sc);
                } else {
                    sc.run();
                }
            } catch (RejectedExecutionException ree) {
                getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
                return false;
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                // This means we got an OOM or similar creating a thread, or that
                // the pool and its queue are full
                getLog().error(sm.getString("endpoint.process.fail"), t);
                return false;
            }
            return true;
    }

}

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel> {
    @Override
    protected SocketProcessorBase<NioChannel> createSocketProcessor(
                SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
       return new SocketProcessor(socketWrapper, event);
    }
}

public abstract class SocketProcessorBase<S> implements Runnable {
    @Override
    /*xxx: 工作线程处理的起点*/
    public final void run() {
            synchronized (socketWrapper) {
                // It is possible that processing may be triggered for read and
                // write at the same time. The sync above makes sure that processing
                // does not occur in parallel. The test below ensures that if the
                // first event to be processed results in the socket being closed,
                // the subsequent events are not processed.
                if (socketWrapper.isClosed()) {
                    return;
                }
                doRun();
            }
    }

    /*xxx: 模板方法,交由子类进行实现 */
    protected abstract void doRun();
}

//package org.apache.tomcat.util.net.NioEndpoint;
protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
    @Override
    protected void doRun() {
         NioChannel socket = socketWrapper.getSocket();
         //省略其它抽象...
        try {
          int handshake = -1;
          try {
              if (handshake == 0) {
                  SocketState state = SocketState.OPEN;
                  // Process the request from this socket
                  System.out.println("handler实例为:"+getHandler()+"   线程为:"+Thread.currentThread().getName());
                  /*xxx: 握手成功,则处理请求 */
                  if (event == null) {
                      state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
                  } else {
                      state = getHandler().process(socketWrapper, event);
                  }
                  if (state == SocketState.CLOSED) {
                      poller.cancelledKey(socket.getIOChannel().keyFor(poller.getSelector()), socketWrapper);
                  }
              }else{
                  //省略其他抽象...
              }
          }catch (Exception e1){
                //省略其他抽象...
            }
        }catch (Exception e2){
           //省略其他抽象...
        }
    }
}


//package org.apache.tomcat.util.net.AbstractEndpoint<S,U>
/*xxx: 请求处理器 */
public static interface Handler<S> {
    public SocketState process(SocketWrapperBase<S> socket,
                                           SocketEvent status);
}

//package org.apache.coyote.AbstractProtocol
protected static class ConnectionHandler<S> implements Handler<S> {
    @Override
    /*xxx: 协议处理器*/
    /*xxx: 当前方法是在多线程环境下执行的 */
    public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
        S socket = wrapper.getSocket();
        
        /*xxx: 获取当前的协议处理器 */
        Processor processor = (Processor) wrapper.getCurrentProcessor();
              
        if (SocketEvent.TIMEOUT == status &&
                (processor == null ||
                !processor.isAsync() && !processor.isUpgrade() ||
                processor.isAsync() && !processor.checkAsyncTimeoutGeneration())) {
            // This is effectively a NO-OP
            return SocketState.OPEN;
        }  

         SocketState state = SocketState.CLOSED;
         /*xxx: 协议处理器处理http请求(多线程环境下) */
         state = processor.process(wrapper, status);
         return state;
         //省略其他抽象,及简化主要逻辑...
    }
}

//package org.apache.coyote;
/*xxx: 处理器 */
public interface Processor {
    SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status) throws IOException;
}

public abstract class AbstractProcessorLight implements Processor {
      @Override
      /*xxx: 处理请求,多线程环境下*/
      public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
              throws IOException {
             SocketState state = SocketState.CLOSED;
          Iterator<DispatchType> dispatches = null;
          do {
              if (dispatches != null) {
                  DispatchType nextDispatch = dispatches.next();
                  if (getLog().isDebugEnabled()) {
                      getLog().debug("Processing dispatch type: [" + nextDispatch + "]");
                  }
                  state = dispatch(nextDispatch.getSocketStatus());
                  if (!dispatches.hasNext()) {
                      state = checkForPipelinedData(state, socketWrapper);
                  }
              } else if (status == SocketEvent.DISCONNECT) {
                  // Do nothing here, just wait for it to get recycled
              } else if (isAsync() || isUpgrade() || state == SocketState.ASYNC_END) {
                  state = dispatch(status);
                  state = checkForPipelinedData(state, socketWrapper);
              } else if (status == SocketEvent.OPEN_WRITE) {
                  // Extra write event likely after async, ignore
                  state = SocketState.LONG;
              } else if (status == SocketEvent.OPEN_READ) {
                  /*xxx: 处理请求,多线程环境下 */
                  state = service(socketWrapper);
              } else if (status == SocketEvent.CONNECT_FAIL) {
                  logAccess(socketWrapper);
              } else {
                  // Default to closing the socket if the SocketEvent passed in
                  // is not consistent with the current state of the Processor
                  state = SocketState.CLOSED;
              }
                 if (getLog().isDebugEnabled()) {
                  getLog().debug("Socket: [" + socketWrapper +
                          "], Status in: [" + status +
                          "], State out: [" + state + "]");
              }
                 if (isAsync()) {
                  state = asyncPostProcess();
                  if (getLog().isDebugEnabled()) {
                      getLog().debug("Socket: [" + socketWrapper +
                              "], State after async post processing: [" + state + "]");
                  }
              }
                 if (dispatches == null || !dispatches.hasNext()) {
                  // Only returns non-null iterator if there are
                  // dispatches to process.
                  dispatches = getIteratorAndClearDispatches();
              }
          } while (state == SocketState.ASYNC_END ||
                  dispatches != null && state != SocketState.CLOSED);
             return state;
      }
      //省略其它抽象...
      /*xxx: 模板方法,处理请求,  多线程环境*/
      protected abstract SocketState service(SocketWrapperBase<?> socketWrapper) throws IOException;
}

public class Http11Processor extends AbstractProcessor {
    
    //(父类)
    protected final Request request=new org.apache.coyote.Request();
    //(父类)
    protected final Response response=new org.apache.coyote.Response();

    /*xxx: 通过该属性,与Mapper,MapperListener发生关联,用于按照 servlet规范查找对应容器 (service)*/
    //父类
    protected final Adapter adapter;

    @Override
    /*xxx: http协议处理器, tomcat的处理核心部分 (多线程环境)*/
    public SocketState service(SocketWrapperBase<?> socketWrapper)
        throws IOException {
        RequestInfo rp = request.getRequestProcessor();
        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);

        // Setting up the I/O
        setSocketWrapper(socketWrapper);

        // Flags
        keepAlive = true;
        openSocket = false;
        readComplete = true;
        boolean keptAlive = false;
        SendfileState sendfileState = SendfileState.DONE;

        while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
                sendfileState == SendfileState.DONE && !protocol.isPaused()) {

            //省略其他抽象...
            // Has an upgrade been requested?
            if (isConnectionToken(request.getMimeHeaders(), "upgrade")) {
                // Check the protocol
                String requestedProtocol = request.getHeader("Upgrade");

                UpgradeProtocol upgradeProtocol = protocol.getUpgradeProtocol(requestedProtocol);
                if (upgradeProtocol != null) {
                    if (upgradeProtocol.accept(request)) {
                        response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
                        response.setHeader("Connection", "Upgrade");
                        response.setHeader("Upgrade", requestedProtocol);
                        action(ActionCode.CLOSE,  null);
                        getAdapter().log(request, response, 0);

                        InternalHttpUpgradeHandler upgradeHandler =
                                upgradeProtocol.getInternalUpgradeHandler(
                                        socketWrapper, getAdapter(), cloneRequest(request));
                        UpgradeToken upgradeToken = new UpgradeToken(upgradeHandler, null, null);
                        action(ActionCode.UPGRADE, upgradeToken);
                        return SocketState.UPGRADING;
                    }
                }
            }
            //省略其他抽象...
            getAdapter().service(request, response);
            //省略其他抽象...
        }

        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);

        if (getErrorState().isError() || (protocol.isPaused() && !isAsync())) {
            return SocketState.CLOSED;
        } else if (isAsync()) {
            return SocketState.LONG;
        } else if (isUpgrade()) {
            return SocketState.UPGRADING;
        } else {
            if (sendfileState == SendfileState.PENDING) {
                return SocketState.SENDFILE;
            } else {
                if (openSocket) {
                    if (readComplete) {
                        return SocketState.OPEN;
                    } else {
                        return SocketState.LONG;
                    }
                } else {
                    return SocketState.CLOSED;
                }
            }
        }
    }  

    public Adapter getAdapter() {
       return adapter;
    }
}

//package org.apache.coyote;
public interface Adapter {
    /*xxx: 调用适配器进行http服务的处理*/
    public void service(Request req, Response res) throws Exception;
}

/*xxx: 适配器,用于找到请求对应的 组件*/
public class CoyoteAdapter implements Adapter {
    private final Connector connector;

    @Override
    /*xxx: 可以看成tomcat的核心流程的处理起点 多线程环境*/
    public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
            throws Exception {
        //省略其它抽象...
        //进入到容器部分逻辑
        connector.getService().getContainer().getPipeline().getFirst().invoke(
                                request, response);
        //省略其它抽象...
    }
}

# Engine(容器,catalina模块)

  • 容器的构造逻辑
/*xxx: 连接器,对应于协议,用于 处理协议, 一个具有生命周期的组件*/
public class Connector extends LifecycleMBeanBase  {
    /*xxx: 如果service进行维护外,本身也持有对应的组件信息*/
    protected Service service = null;

    public Service getService() {
       return this.service;
    }
}

public interface Service extends Lifecycle {
    public Engine getContainer();
}

/*xxx: 声明周期,super抽象,用于将整个应用流程进行统一管理*/
/*xxx: 主要由一些特定的事件,以及相应的 生命周期函数组成*/
/*xxx: 直接子类有: Server,service,container,executor
 *  WebResource,WebappClassLoader*/
public interface Lifecycle {
    /*xxx: 能够添加生命周期监听器*/
    public void addLifecycleListener(LifecycleListener listener);

    public void init() throws LifecycleException;

    public void start() throws LifecycleException;

    public void stop() throws LifecycleException;

    public void destroy() throws LifecycleException;
}

/*xxx: 抽象组件,所有组件都具有的公共属性及模板方法 */
/*xxx: 抽象组件对内置的组件具有一定的耦合性*/
public interface Container extends Lifecycle {
    /*xxx:获取管道*/
    public Pipeline getPipeline();

    /*xxx: 获取父组件*/
    public Container getParent();

    public void addChild(Container child);
}

/*xxx: pipeline 与 valve 不是 javax.servlet标准的接口,而是tomcat独有的*/
/*xxx: Tomcat定义了 Pipeline 和 Valve两个接口,前者用于构造职责链,后者代表职责链的每个处理器*/
public interface Pipeline extends Contained {
    public Valve[] getValves();
}

public interface Engine extends Container {
    /*xxx: 持有Service,双向绑定*/
    public Service getService();
}

public class StandardEngine extends ContainerBase implements Engine {
    @Override
    public void addChild(Container child) {
        if (!(child instanceof Host))
            throw new IllegalArgumentException
                (sm.getString("standardEngine.notHost"));
        super.addChild(child);
    }
}

/*xxx: 就host组件而言,它的核心功能在于自身,而非抽象组件*/
public interface Host extends Container {
    /*xxx: host组件,具有一个基本的 应用路径*/
    public String getAppBase();

    /*xxx: host组件,具有自动部署的能力 */
    public boolean getAutoDeploy();

    /*xxx: 启动时自动部署的的能力*/
    public boolean getDeployOnStartup();
}

public class StandardHost extends ContainerBase implements Host {
    @Override
    public void addChild(Container child) {
    
       if (!(child instanceof Context))
           throw new IllegalArgumentException
               (sm.getString("standardHost.notContext"));
       child.addLifecycleListener(new MemoryLeakTrackingListener());
       // Avoid NPE for case where Context is defined in server.xml with only a
       // docBase
       Context context = (Context) child;
       if (context.getPath() == null) {
           ContextName cn = new ContextName(context.getDocBase(), true);
           context.setPath(cn.getPath());
       }
       super.addChild(child);
    
    }
}

public interface Context extends Container, ContextBind {
    /*xxx: 获取编码*/
    public String getCharset(Locale locale);

    /*xxx: 是否允许 cookie作为session track模式*/
    public boolean getCookies();

    /*xxx: 获取当前web应用的 上下文路径*/
    public String getPath();

    /*xxx: 获取servlet上下文*/
    public ServletContext getServletContext();

    /*xxx: servlet包装器*/
    public Wrapper createWrapper();

    /*xxx: 管理器*/
    public Manager getManager();

    /*xxx: cookie处理器*/
    public CookieProcessor getCookieProcessor();

}

public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {
    @Override
    public void addChild(Container child) {
    
       // Global JspServlet
       Wrapper oldJspServlet = null;
       if (!(child instanceof Wrapper)) {
           throw new IllegalArgumentException
               (sm.getString("standardContext.notWrapper"));
       }
       boolean isJspServlet = "jsp".equals(child.getName());
       // Allow webapp to override JspServlet inherited from global web.xml.
       if (isJspServlet) {
           oldJspServlet = (Wrapper) findChild("jsp");
           if (oldJspServlet != null) {
               removeChild(oldJspServlet);
           }
       }
       super.addChild(child);
       if (isJspServlet && oldJspServlet != null) {
           /*
            * The webapp-specific JspServlet inherits all the mappings
            * specified in the global web.xml, and may add additional ones.
            */
           String[] jspMappings = oldJspServlet.findMappings();
           for (int i=0; jspMappings!=null && i<jspMappings.length; i++) {
               addServletMappingDecoded(jspMappings[i], child.getName());
           }
       }
    }
}
        
/*xxx: Wrapper组件,逻辑上为Context的直接子类,其是用于处理 Servlet规范 的直观实现
*   从代码中可以分析出: 一个Wrapper对应一个Servlet,Wrapper可以由多个映射进行对应
*   一个servlet可以有多个实例*/
public interface Wrapper extends Container {
    /*xxx: 获取启动的加载顺序*/
    public int getLoadOnStartup();

    /*xxx: 获取当前Wrapper对应的ServletClass的完整类名,
        *       换言之,一个Wrappper对应一个Servlet*/
    public String getServletClass();

    /*xxx: 获取当前关联的servlet实例*/
    public Servlet getServlet();

    /*xxx: 为当前的Wrapper添加映射*/
    public void addMapping(String mapping);

    /*xxx: 释放 当前servlet的所有实例*/
    public void unload() throws ServletException;
}

public class StandardWrapper extends ContainerBase
    implements ServletConfig, Wrapper, NotificationEmitter {
    @Override
    public void addChild(Container child) {
    
            throw new IllegalStateException
                (sm.getString("standardWrapper.notChild"));
    
    }
}
  • 容器的启动逻辑
public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory implements ConfigurableTomcatWebServerFactory {
    @Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
            Tomcat tomcat = new Tomcat();
            File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
            tomcat.setBaseDir(baseDir.getAbsolutePath());
            Connector connector = new Connector(this.protocol);
            tomcat.getService().addConnector(connector);
            customizeConnector(connector);
            tomcat.setConnector(connector);
            /*xxx: host组件,用的默认的 standardHost组件*/
            tomcat.getHost().setAutoDeploy(false);
            configureEngine(tomcat.getEngine());
            for (Connector additionalConnector : this.additionalTomcatConnectors) {
                tomcat.getService().addConnector(additionalConnector);
            }
            prepareContext(tomcat.getHost(), initializers);
            return getTomcatWebServer(tomcat);
    }
}

/*xxx: 提供一种轻量级的扩展方式启动 tomcat,使得应用可以内嵌运行*/
public class Tomcat {
    public Host getHost() {
       Engine engine = getEngine();
       if (engine.findChildren().length > 0) {
           return (Host) engine.findChildren()[0];
       }
       Host host = new StandardHost();
       host.setName(hostname);
       getEngine().addChild(host);
       return host;
    }

    public Engine getEngine() {
       Service service = getServer().findServices()[0];
       if (service.getContainer() != null) {
           return service.getContainer();
       }
       Engine engine = new StandardEngine();
       engine.setName( "Tomcat" );
       engine.setDefaultHost(hostname);
       engine.setRealm(createDefaultRealm());
       service.setContainer(engine);
       return engine;
    }

    public Server getServer() {
       if (server != null) {
           return server;
       }
       System.setProperty("catalina.useNaming", "false");
       server = new StandardServer();
       initBaseDir();
       // Set configuration source
       ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(new File(basedir), null));
       server.setPort( -1 );
       Service service = new StandardService();
       service.setName("Tomcat");
       server.addService(service);
       return server;
    }
    
}

public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory implements ConfigurableTomcatWebServerFactory {

    protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
            File documentRoot = getValidDocumentRoot();
            /*xxx: 是 StandardContext的变体*/
            TomcatEmbeddedContext context = new TomcatEmbeddedContext();
            if (documentRoot != null) {
                context.setResources(new LoaderHidingResourceRoot(context));
            }
            context.setName(getContextPath());
            context.setDisplayName(getDisplayName());
            context.setPath(getContextPath());
            File docBase = (documentRoot != null) ? documentRoot : createTempDir("tomcat-docbase");
            context.setDocBase(docBase.getAbsolutePath());
            context.addLifecycleListener(new Tomcat.FixContextListener());
            context.setParentClassLoader((this.resourceLoader != null) ? this.resourceLoader.getClassLoader()
                    : ClassUtils.getDefaultClassLoader());
            resetDefaultLocaleMapping(context);
            addLocaleMappings(context);
            context.setUseRelativeRedirects(false);
            try {
                context.setCreateUploadTargets(true);
            }
            catch (NoSuchMethodError ex) {
                // Tomcat is < 8.5.39. Continue.
            }
            configureTldSkipPatterns(context);
            WebappLoader loader = new WebappLoader(context.getParentClassLoader());
            loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
            loader.setDelegate(true);
            context.setLoader(loader);
            if (isRegisterDefaultServlet()) {
                addDefaultServlet(context);
                //如果不注册默认的servlet,则需要自定义,20211013扩展, 相当于在外置tomcat进行与springWebMVC的集成
            }else {
                addCustomServlet(context);
            }
    
            /*xxx: springSession的过滤器,需要在 spirngSecurity之前*/
            if (isSpringSessionEnvironment){
                addSpringSessionFilter(context);
            }
            if (isSpringSecurityEnvironment){
                addSpringSecurityFilter(context);
            }
    
    
            if (shouldRegisterJspServlet()) {
                addJspServlet(context);
                addJasperInitializer(context);
            }
            context.addLifecycleListener(new StaticResourceConfigurer(context));
            ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
            /*xxx: 将 context添加为 host的子组件*/
            host.addChild(context);
            /*xxx: 为 context 添加 Initializers*/
            configureContext(context, initializersToUse);
            postProcessContext(context);
    }
}


public class StandardEngine extends ContainerBase implements Engine {
    public StandardEngine() {
        super();
        pipeline.setBasic(new StandardEngineValve());
        /* Set the jmvRoute using the system property jvmRoute */
        try {
            setJvmRoute(System.getProperty("jvmRoute"));
        } catch(Exception ex) {
            log.warn(sm.getString("standardEngine.jvmRouteFail"));
        }
        // By default, the engine will hold the reloading thread
        backgroundProcessorDelay = 10; 
    }
}

final class StandardEngineValve extends ValveBase {'
    @Override
        public final void invoke(Request request, Response response)
            throws IOException, ServletException {
    
            // Select the Host to be used for this Request
            /*xxx: 在连接器阶段,已经将请求所需要对应的host进行了映射*/
            /*xxx: 如果当前的容器没有设置 host,则也会报404错误, 是tomcat容器层面报的*/
            Host host = request.getHost();
            if (host == null) {
                // HTTP 0.9 or HTTP 1.0 request without a host when no default host
                // is defined.
                // Don't overwrite an existing error
                if (!response.isError()) {
                    response.sendError(404);
                }
                return;
            }
            if (request.isAsyncSupported()) {
                request.setAsyncSupported(host.getPipeline().isAsyncSupported());
            }
    
            // Ask this Host to process this request
            host.getPipeline().getFirst().invoke(request, response);
        }
}

public class StandardHost extends ContainerBase implements Host {
    public StandardHost() {
        super();
        pipeline.setBasic(new StandardHostValve());
    }
}

final class StandardHostValve extends ValveBase {
     @Override
     public final void invoke(Request request, Response response)
       throws IOException, ServletException {
       // Select the Context to be used for this Request
       /*xxx: 从请求中获取 context容器 , 在连接器阶段,已经将该请求,所需要使用到的容器进行了映射*/
       Context context = request.getContext();
       if (context == null) {
           // Don't overwrite an existing error
           if (!response.isError()) {
               response.sendError(404);
           }
           return;
       }
       if (request.isAsyncSupported()) {
           request.setAsyncSupported(context.getPipeline().isAsyncSupported());
       }
       boolean asyncAtStart = request.isAsync();
       try {
           context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
           if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) {
               // Don't fire listeners during async processing (the listener
               // fired for the request that called startAsync()).
               // If a request init listener throws an exception, the request
               // is aborted.
               return;
           }
           // Ask this Context to process this request. Requests that are
           // already in error must have been routed here to check for
           // application defined error pages so DO NOT forward them to the the
           // application for processing.
           try {
               if (!response.isErrorReportRequired()) {
                   context.getPipeline().getFirst().invoke(request, response);
               }
           } catch (Throwable t) {
               ExceptionUtils.handleThrowable(t);
               container.getLogger().error("Exception Processing " + request.getRequestURI(), t);
               // If a new error occurred while trying to report a previous
               // error allow the original error to be reported.
               if (!response.isErrorReportRequired()) {
                   request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
                   throwable(request, response, t);
               }
           }
           // Now that the request/response pair is back under container
           // control lift the suspension so that the error handling can
           // complete and/or the container can flush any remaining data
           response.setSuspended(false);
           Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
           // Protect against NPEs if the context was destroyed during a
           // long running request.
           if (!context.getState().isAvailable()) {
               return;
           }
           // Look for (and render if found) an application level error page
           if (response.isErrorReportRequired()) {
               // If an error has occurred that prevents further I/O, don't waste time
               // producing an error report that will never be read
               AtomicBoolean result = new AtomicBoolean(false);
               response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);
               if (result.get()) {
                   if (t != null) {
                       throwable(request, response, t);
                   } else {
                       status(request, response);
                   }
               }
           }
           if (!request.isAsync() && !asyncAtStart) {
               context.fireRequestDestroyEvent(request.getRequest());
           }
       } finally {
           // Access a session (if present) to update last accessed time, based
           // on a strict interpretation of the specification
           if (ACCESS_SESSION) {
               request.getSession(false);
           }
           context.unbind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
       }
     }
}

public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {
    public StandardContext() {
        super();
        pipeline.setBasic(new StandardContextValve());
        broadcaster = new NotificationBroadcasterSupport();
        // Set defaults
        if (!Globals.STRICT_SERVLET_COMPLIANCE) {
            // Strict servlet compliance requires all extension mapped servlets
            // to be checked against welcome files
            resourceOnlyServlets.add("jsp");
        }
    }
    
}

final class StandardContextValve extends ValveBase {
     @Override
     public final void invoke(Request request, Response response)
            throws IOException, ServletException {
    
       // Disallow any direct access to resources under WEB-INF or META-INF 
       /*xxx: 上下文路径,不能使用 META-INF 或者 WEB-INF,否则报错*/
       MessageBytes requestPathMB = request.getRequestPathMB();
       if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
               || (requestPathMB.equalsIgnoreCase("/META-INF"))
               || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
               || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
           response.sendError(HttpServletResponse.SC_NOT_FOUND);
           return;
       }
       // Select the Wrapper to be used for this Request
       /*xxx: 如果没有与当前请求相匹配的Wrapper,也会报错*/
       Wrapper wrapper = request.getWrapper();
       if (wrapper == null || wrapper.isUnavailable()) {
           response.sendError(HttpServletResponse.SC_NOT_FOUND);
           return;
       }
       // Acknowledge the request
       try {
           response.sendAcknowledgement(ContinueResponseTiming.IMMEDIATELY);
       } catch (IOException ioe) {
           container.getLogger().error(sm.getString(
                   "standardContextValve.acknowledgeException"), ioe);
           request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
           response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
           return;
       }
       if (request.isAsyncSupported()) {
           request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
       }
       wrapper.getPipeline().getFirst().invoke(request, response);
     }
}

public class StandardWrapper extends ContainerBase
    implements ServletConfig, Wrapper, NotificationEmitter {

    public StandardWrapper() {
            super();
            swValve=new StandardWrapperValve();
            pipeline.setBasic(swValve);
            broadcaster = new NotificationBroadcasterSupport();
    }

}

final class StandardWrapperValve
    extends ValveBase {
    @Override
    public final void invoke(Request request, Response response)
            throws IOException, ServletException {
    
            // Initialize local variables we may need
            boolean unavailable = false;
            Throwable throwable = null;
            // This should be a Request attribute...
            long t1=System.currentTimeMillis();
            requestCount.incrementAndGet();
            StandardWrapper wrapper = (StandardWrapper) getContainer();
            Servlet servlet = null;
            Context context = (Context) wrapper.getParent();
    
            // Check for the application being marked unavailable
            if (!context.getState().isAvailable()) {
                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                               sm.getString("standardContext.isUnavailable"));
                unavailable = true;
            }
    
            // Check for the servlet being marked unavailable
            if (!unavailable && wrapper.isUnavailable()) {
                container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
                        wrapper.getName()));
                long available = wrapper.getAvailable();
                if ((available > 0L) && (available < Long.MAX_VALUE)) {
                    response.setDateHeader("Retry-After", available);
                    response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                            sm.getString("standardWrapper.isUnavailable",
                                    wrapper.getName()));
                } else if (available == Long.MAX_VALUE) {
                    response.sendError(HttpServletResponse.SC_NOT_FOUND,
                            sm.getString("standardWrapper.notFound",
                                    wrapper.getName()));
                }
                unavailable = true;
            }
    
            // Allocate a servlet instance to process this request
            try {
                if (!unavailable) {
                    /*xxx: 默认的 servlet从这个方法而来*/
                    servlet = wrapper.allocate();
                }
            } catch (UnavailableException e) {
                container.getLogger().error(
                        sm.getString("standardWrapper.allocateException",
                                wrapper.getName()), e);
                long available = wrapper.getAvailable();
                if ((available > 0L) && (available < Long.MAX_VALUE)) {
                    response.setDateHeader("Retry-After", available);
                    response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                               sm.getString("standardWrapper.isUnavailable",
                                            wrapper.getName()));
                } else if (available == Long.MAX_VALUE) {
                    response.sendError(HttpServletResponse.SC_NOT_FOUND,
                               sm.getString("standardWrapper.notFound",
                                            wrapper.getName()));
                }
            } catch (ServletException e) {
                container.getLogger().error(sm.getString("standardWrapper.allocateException",
                                 wrapper.getName()), StandardWrapper.getRootCause(e));
                throwable = e;
                exception(request, response, e);
            } catch (Throwable e) {
                ExceptionUtils.handleThrowable(e);
                container.getLogger().error(sm.getString("standardWrapper.allocateException",
                                 wrapper.getName()), e);
                throwable = e;
                exception(request, response, e);
                servlet = null;
            }
    
            MessageBytes requestPathMB = request.getRequestPathMB();
            DispatcherType dispatcherType = DispatcherType.REQUEST;
            if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
            request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
            request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
                    requestPathMB);
            // Create the filter chain for this request
            /*xxx: 从这里,开始进入 Servlet规范,进行处理*/
            ApplicationFilterChain filterChain =
                    ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
    
            // Call the filter chain for this request
            // NOTE: This also calls the servlet's service() method
            Container container = this.container;
            try {
                if ((servlet != null) && (filterChain != null)) {
                    // Swallow output if needed
                    if (context.getSwallowOutput()) {
                        try {
                            SystemLogHandler.startCapture();
                            if (request.isAsyncDispatching()) {
                                request.getAsyncContextInternal().doInternalDispatch();
                            } else {
                                filterChain.doFilter(request.getRequest(),
                                        response.getResponse());
                            }
                        } finally {
                            String log = SystemLogHandler.stopCapture();
                            if (log != null && log.length() > 0) {
                                context.getLogger().info(log);
                            }
                        }
                    } else {
                        if (request.isAsyncDispatching()) {
                            request.getAsyncContextInternal().doInternalDispatch();
                        } else {
                            filterChain.doFilter
                                (request.getRequest(), response.getResponse());
                        }
                    }
    
                }
            } catch (ClientAbortException | CloseNowException e) {
                if (container.getLogger().isDebugEnabled()) {
                    container.getLogger().debug(sm.getString(
                            "standardWrapper.serviceException", wrapper.getName(),
                            context.getName()), e);
                }
                throwable = e;
                exception(request, response, e);
            } catch (IOException e) {
                container.getLogger().error(sm.getString(
                        "standardWrapper.serviceException", wrapper.getName(),
                        context.getName()), e);
                throwable = e;
                exception(request, response, e);
            } catch (UnavailableException e) {
                container.getLogger().error(sm.getString(
                        "standardWrapper.serviceException", wrapper.getName(),
                        context.getName()), e);
                //            throwable = e;
                //            exception(request, response, e);
                wrapper.unavailable(e);
                long available = wrapper.getAvailable();
                if ((available > 0L) && (available < Long.MAX_VALUE)) {
                    response.setDateHeader("Retry-After", available);
                    response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                               sm.getString("standardWrapper.isUnavailable",
                                            wrapper.getName()));
                } else if (available == Long.MAX_VALUE) {
                    response.sendError(HttpServletResponse.SC_NOT_FOUND,
                                sm.getString("standardWrapper.notFound",
                                            wrapper.getName()));
                }
                // Do not save exception in 'throwable', because we
                // do not want to do exception(request, response, e) processing
            } catch (ServletException e) {
                Throwable rootCause = StandardWrapper.getRootCause(e);
                if (!(rootCause instanceof ClientAbortException)) {
                    container.getLogger().error(sm.getString(
                            "standardWrapper.serviceExceptionRoot",
                            wrapper.getName(), context.getName(), e.getMessage()),
                            rootCause);
                }
                throwable = e;
                exception(request, response, e);
            } catch (Throwable e) {
                ExceptionUtils.handleThrowable(e);
                container.getLogger().error(sm.getString(
                        "standardWrapper.serviceException", wrapper.getName(),
                        context.getName()), e);
                throwable = e;
                exception(request, response, e);
            } finally {
                // Release the filter chain (if any) for this request
                if (filterChain != null) {
                    filterChain.release();
                }
    
                // Deallocate the allocated servlet instance
                try {
                    if (servlet != null) {
                        wrapper.deallocate(servlet);
                    }
                } catch (Throwable e) {
                    ExceptionUtils.handleThrowable(e);
                    container.getLogger().error(sm.getString("standardWrapper.deallocateException",
                                     wrapper.getName()), e);
                    if (throwable == null) {
                        throwable = e;
                        exception(request, response, e);
                    }
                }
    
                // If this servlet has been marked permanently unavailable,
                // unload it and release this instance
                try {
                    if ((servlet != null) &&
                        (wrapper.getAvailable() == Long.MAX_VALUE)) {
                        wrapper.unload();
                    }
                } catch (Throwable e) {
                    ExceptionUtils.handleThrowable(e);
                    container.getLogger().error(sm.getString("standardWrapper.unloadException",
                                     wrapper.getName()), e);
                    if (throwable == null) {
                        exception(request, response, e);
                    }
                }
                long t2=System.currentTimeMillis();
    
                long time=t2-t1;
                processingTime += time;
                if( time > maxTime) maxTime=time;
                if( time < minTime) minTime=time;
            }
    }
}

  • 容器如何运行及初始化
public class Tomcat {
    public void start() throws LifecycleException {
       getServer();
       server.start();
    }
}

public final class StandardServer extends LifecycleMBeanBase implements Server {
     @Override
     protected void startInternal() throws LifecycleException {
    
       fireLifecycleEvent(CONFIGURE_START_EVENT, null);
       setState(LifecycleState.STARTING);
       globalNamingResources.start();
       // Start our defined Services
       synchronized (servicesLock) {
           for (Service service : services) {
               service.start();
           }
       }
       if (periodicEventDelay > 0) {
           monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
                   new Runnable() {
                       @Override
                       public void run() {
                           startPeriodicLifecycleEvent();
                       }
                   }, 0, 60, TimeUnit.SECONDS);
       }
     }
}

public class StandardService extends LifecycleMBeanBase implements Service {
    @Override
    protected void startInternal() throws LifecycleException {
    
       if(log.isInfoEnabled())
           log.info(sm.getString("standardService.start.name", this.name));
       setState(LifecycleState.STARTING);
       // Start our defined Container first
       if (engine != null) {
           synchronized (engine) {
               engine.start();
           }
       }
       synchronized (executors) {
           for (Executor executor: executors) {
               executor.start();
           }
       }
       mapperListener.start();
       // Start our defined Connectors second
       synchronized (connectorsLock) {
           for (Connector connector: connectors) {
               // If it has already failed, don't try and start it
               if (connector.getState() != LifecycleState.FAILED) {
                   connector.start();
               }
           }
       }
    }
}

public abstract class ContainerBase extends LifecycleMBeanBase
        implements Container {
    @Override
    protected synchronized void startInternal() throws LifecycleException {
    
            // Start our subordinate components, if any
            logger = null;
            getLogger();
            /*xxx: 如果配置了集群组件,则启动*/
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).start();
            }
            /*xxx: 如果配置了安全组件,则启动*/
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).start();
            }
    
            // Start our child containers, if any
            /*xxx: 启动子节点,如果有的话*/
            Container children[] = findChildren();
            List<Future<Void>> results = new ArrayList<>();
            for (Container child : children) {
                results.add(startStopExecutor.submit(new StartChild(child)));
            }
    
            MultiThrowable multiThrowable = null;
    
            for (Future<Void> result : results) {
                try {
                    result.get();
                } catch (Throwable e) {
                    log.error(sm.getString("containerBase.threadedStartFailed"), e);
                    if (multiThrowable == null) {
                        multiThrowable = new MultiThrowable();
                    }
                    multiThrowable.add(e);
                }
    
            }
            if (multiThrowable != null) {
                throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                        multiThrowable.getThrowable());
            }
    
            // Start the Valves in our pipeline (including the basic), if any
            /*xxx: 如果有pipeline组件,则启动*/
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).start();
            }
    
            /*xxx: 设置 主机状态为  starting */
            /*xxx: 此时会触发  start_event生命周期事件*/
            /*xxx: hostConfig监听了该事件,会进行自动部署*/
            setState(LifecycleState.STARTING);
    
            // Start our thread
            /*xxx: 启动 主机层级的后台任务处理  包括:  集群的心跳检测,安全组件后台任务处理,pipeline的后台任务处理*/
            if (backgroundProcessorDelay > 0) {
                monitorFuture = Container.getService(ContainerBase.this).getServer()
                        .getUtilityExecutor().scheduleWithFixedDelay(
                                new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS);
        }
    }
}

public class StandardEngine extends ContainerBase implements Engine {
    @Override
    protected synchronized void startInternal() throws LifecycleException {
         // Log our server identification information
        if (log.isInfoEnabled()) {
            log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo()));
        }
         // Standard container startup
        super.startInternal();
    }
}

public class StandardHost extends ContainerBase implements Host {
    @Override
    protected synchronized void startInternal() throws LifecycleException {
         // Set error report valve
        /*xxx: 首先,添加一个 全局的错误处理Valve,在 web.xml没有添加错误页面时,tomcat返回的异常栈就是由这个valve生成的*/
        String errorValve = getErrorReportValveClass();
        if ((errorValve != null) && (!errorValve.equals(""))) {
            try {
                boolean found = false;
                Valve[] valves = getPipeline().getValves();
                for (Valve valve : valves) {
                    if (errorValve.equals(valve.getClass().getName())) {
                        found = true;
                        break;
                    }
                }
                if(!found) {
                    Valve valve = ErrorReportValve.class.getName().equals(errorValve) ?
                        new ErrorReportValve() :
                        (Valve) Class.forName(errorValve).getConstructor().newInstance();
                    getPipeline().addValve(valve);
                }
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error(sm.getString(
                        "standardHost.invalidErrorReportValveClass",
                        errorValve), t);
            }
        }
        /*xxx: 然后调用父类的方法启动虚拟主机*/
        super.startInternal();
    }
}

public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {
    @Override
    /*xxx: context的启动逻辑,比较复杂*/
    protected synchronized void startInternal() throws LifecycleException {

            // Send j2ee.state.starting notification
            if (this.getObjectName() != null) {
                Notification notification = new Notification("j2ee.state.starting",
                        this.getObjectName(), sequenceNumber.getAndIncrement());
                /*xxx:1. 发布正在启动的jmx通知*/
                broadcaster.sendNotification(notification);
            }
    
            setConfigured(false);
            boolean ok = true;
    
            // Currently this is effectively a NO-OP but needs to be called to
            // ensure the NamingResources follows the correct lifecycle
            if (namingResources != null) {
                /*xxx: 2.启动当前上下文维护的jndi资源*/
                namingResources.start();
            }
    
            /*xxx: 7.初始化临时目录,默认为 work/engine名称/主机名称/上下文名称*/
            // Post work directory
            postWorkDirectory();
    
            // Add missing components as necessary
            if (getResources() == null) {   // (1) Required by Loader
                try {
                    /*xxx: 3.初始化当前上下文使用的 webResourceRoot并启动,用于管理目录资源*/
                    /*xxx: 查找资源时,按照指定顺序处理:  pre资源 -> main资源(web-inf/classess,web-inf/lib)->jar资源->post资源*/
                    setResources(new StandardRoot(this));
                } catch (IllegalArgumentException e) {
                    log.error(sm.getString("standardContext.resourcesInit"), e);
                    ok = false;
                }
            }
            if (ok) {
                resourcesStart();
            }
    
            if (getLoader() == null) {
                /*xxx: 4.创建web应用类加载器*/
                WebappLoader webappLoader = new WebappLoader();
                webappLoader.setDelegate(getDelegate());
                setLoader(webappLoader);
            }
    
            /*xxx: 5.设置cookie处理器*/
            if (cookieProcessor == null) {
                cookieProcessor = new Rfc6265CookieProcessor();
            }
    
            /*xxx: 6.获取字符集映射*/
            getCharsetMapper();
    
            /*xxx: 8.web应用的依赖检测,主要检测依赖扩展点完整性*/
            boolean dependencyCheck = true;
            try {
                dependencyCheck = ExtensionValidator.validateApplication
                    (getResources(), this);
            } catch (IOException ioe) {
                log.error(sm.getString("standardContext.extensionValidationError"), ioe);
                dependencyCheck = false;
            }
    
            if (!dependencyCheck) {
                // do not make application available if dependency check fails
                ok = false;
            }
    
            // Reading the "catalina.useNaming" environment variable
            String useNamingProperty = System.getProperty("catalina.useNaming");
            if ((useNamingProperty != null)
                && (useNamingProperty.equals("false"))) {
                useNaming = false;
            }
    
            /*xxx: 9.如果当前上下文使用JNDI,则为其添加 NamingContextListener*/
            if (ok && isUseNaming()) {
                if (getNamingContextListener() == null) {
                    NamingContextListener ncl = new NamingContextListener();
                    ncl.setName(getNamingContextName());
                    ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite());
                    addLifecycleListener(ncl);
                    setNamingContextListener(ncl);
                }
            }
   
            // Binding thread
            ClassLoader oldCCL = bindThread();
    
            
            if (ok) {
                    // Start our subordinate components, if any
                    Loader loader = getLoader();
                    /*xxx: 10启动web应用类加载器*/
                    if (loader instanceof Lifecycle) {
                    //省略部分抽象...
    
                    Realm realm = getRealmInternal();
                    if(null != realm) {
                        if (realm instanceof Lifecycle) {
                            /*xxx:11.启动安全组件,realm*/
                            ((Lifecycle) realm).start();
                        }
                        //省略部分抽象...
                    }
    
                    /*xxx:12,发布 configure_start_event事件, ContextConfig监听该事件,以完成  Servlet的创建*/
                    fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
    
                    for (Container child : findChildren()) {
                        if (!child.getState().isAvailable()) {
                            /*xxx: 13.启动Context的子节点,即 Wrapper*/
                            child.start();
                        }
                    }

                    if (pipeline instanceof Lifecycle) {
                        /*xxx: 14.启动Context维护的pipeline*/
                        ((Lifecycle) pipeline).start();
                    }
    
                    // Acquire clustered manager
                    Manager contextManager = null;
                    Manager manager = getManager();
                    if (manager == null) {
                        if ((getCluster() != null) && distributable) {
                            /*xxx:15 创建会话管理器,如果配置了集群组件,则由集群组件创建,否则使用标准的会话管理器*/
                            try {
                                contextManager = getCluster().createManager(getName());
                            } catch (Exception ex) {
                                log.error(sm.getString("standardContext.cluster.managerError"), ex);
                                ok = false;
                            }
                        } else {
                            contextManager = new StandardManager();
                        }
                    }
    
                    // Configure default manager if none was specified
                    if (contextManager != null) {
                        setManager(contextManager);
                    }
    
                    if (manager!=null && (getCluster() != null) && distributable) {
                        //let the cluster know that there is a context that is distributable
                        //and that it has its own manager
                        getCluster().registerManager(manager);
                    }
                }
    
                if (!getConfigured()) {
                    log.error(sm.getString("standardContext.configurationFail"));
                    ok = false;
                }
    
                // We put the resources into the servlet context
                if (ok) {
                    /*xxx: 16.将 Context的web资源集合,添加到 ServletContext的属性,名为 org.apache.catalina.resources*/
                    getServletContext().setAttribute
                        (Globals.RESOURCES_ATTR, getResources());
    
                    if (getInstanceManager() == null) {
                        /*xxx: 17.创建实例管理器,用于创建对象实例,如Servlet,Filter等*/
                        setInstanceManager(createInstanceManager());
                    }
                    getServletContext().setAttribute(
                            InstanceManager.class.getName(), getInstanceManager());
                    InstanceManagerBindings.bind(getLoader().getClassLoader(), getInstanceManager());
    
                    /*xxx: 18.将 jar包扫描器 添加到 ServletContext属性,属性名为 org.apache.tomcat.JarScanner属性*/
                    getServletContext().setAttribute(
                            JarScanner.class.getName(), getJarScanner());
    
                    // Make the version info available
                    getServletContext().setAttribute(Globals.WEBAPP_VERSION, getWebappVersion());
                }
    
                /*xxx: 19.合并 servletContext初始化参数  和 Context组件中的ApplicationParameter,根据applicationParameter的配置决定是否可以覆盖同名参数*/
                mergeParameters();
    
                // Call ServletContainerInitializers
                for (Entry<ServletContainerInitializer, Set<Class<?>>> entry :
                    initializers.entrySet()) {
                    try {
                        /*xxx: 20.启动添加到当前上下文的  ServletContainerInitializer,该类的实例,由 ContextConfig查找并添加*/
                        /*xxx: 该类主要用于 以可编程的方式添加Web应用的配置,如Servlet,Filter等 */
                        /*xxx: 注意,这里就似乎 SPI机制的体现了*/
                        entry.getKey().onStartup(entry.getValue(),
                                getServletContext());
                    } catch (ServletException e) {
                        log.error(sm.getString("standardContext.sciFail"), e);
                        ok = false;
                        break;
                    }
                }
    
                if (ok) {
                    /*xxx: 21.实例化应用监听器 ,分为事件监听器,一级生命周期监听器, 这些监听器 可以通过 Context部署描述文件,可编程方式,或者web.xml添加*/
                    if (!listenerStart()) {
                        log.error(sm.getString("standardContext.listenerFail"));
                        ok = false;
                    }
                }

                if (ok) {
                    /*xxx: 22.检测未覆盖的 HTTP方法的安全约束*/
                    checkConstraintsForUncoveredMethods(findConstraints());
                }
    
                try {
                    // Start manager
                    /*xxx: 23.启动会话管理器*/
                    Manager manager = getManager();
                    if (manager instanceof Lifecycle) {
                        ((Lifecycle) manager).start();
                    }
                } catch(Exception e) {
                    log.error(sm.getString("standardContext.managerFail"), e);
                    ok = false;
                }
    
                // Configure and call application filters
                if (ok) {
                    /*xxx: 24.实例化 FilterConfig,Filter,并调用  Filter.init初始化*/
                    if (!filterStart()) {
                        log.error(sm.getString("standardContext.filterFail"));
                        ok = false;
                    }
                }
    
                // Load and initialize all "load on startup" servlets
                if (ok) {
                    /*xxx: 25.对于 loadOnStartup>=0的包装器,调用 wrapper.load,该方法负责实例化Servlet,并调用 Servlet.init进行初始化*/
                    if (!loadOnStartup(findChildren())){
                        log.error(sm.getString("standardContext.servletFail"));
                        ok = false;
                    }
                }
    
                /*xxx: 26.启动后台定时处理线程,只有当  backgroundProcessorDelay>0时才启动*/
                super.threadStart();
            } 
    
            startTime=System.currentTimeMillis();
    
            // Send j2ee.state.running notification
            if (ok && (this.getObjectName() != null)) {
                /*xxx: 27.发布正在运行的jmx通知*/
                Notification notification =
                    new Notification("j2ee.state.running", this.getObjectName(),
                                     sequenceNumber.getAndIncrement());
                broadcaster.sendNotification(notification);
            }

            /*xxx: 28.调用 webResourceRoot.gc释放资源(加载资源时,为了提高性能会缓存某些信息,该方法用于清理这些资源,如关闭jar文件)*/
            getResources().gc();
    
            // Reinitializing if something went wrong
            if (!ok) {
                /*xxx:29.设置上下文的状态*/
                setState(LifecycleState.FAILED);
                // Send j2ee.object.failed notification
                if (this.getObjectName() != null) {
                    Notification notification = new Notification("j2ee.object.failed",
                            this.getObjectName(), sequenceNumber.getAndIncrement());
                    broadcaster.sendNotification(notification);
                }
            } else {
                setState(LifecycleState.STARTING);
            }
    }

}

public class StandardWrapper extends ContainerBase
    implements ServletConfig, Wrapper, NotificationEmitter {
    
    @Override
    protected synchronized void startInternal() throws LifecycleException {
    
            // Send j2ee.state.starting notification
            if (this.getObjectName() != null) {
                Notification notification = new Notification("j2ee.state.starting",
                                                            this.getObjectName(),
                                                            sequenceNumber++);
                broadcaster.sendNotification(notification);
            }
    
            // Start up this component
            super.startInternal();
    
            setAvailable(0L);
    
            // Send j2ee.state.running notification
            if (this.getObjectName() != null) {
                Notification notification =
                    new Notification("j2ee.state.running", this.getObjectName(),
                                    sequenceNumber++);
                broadcaster.sendNotification(notification);
            }
    
    }
}
  • 常用容器
    • StandardServer
      • 与tomcat容器等价,一个tomcat包括单个server
    • StandardService
      • 一个server包含单个service,service持有一个Connector和一个Engine
    • StandardEngine
      • 标准引擎,是host的父类
    • StandardEngineValve
      • 标准引擎阀门,运行逻辑向子容器流转
    • StandardHost
      • 标准主机,是engine的子容器,context的父容器
      • 实例化主机时,会反向实例化engine(如果还未实例化)
    • StandardHostValve
      • 标准主机阀门,运行逻辑向子容器流转
    • StandardContext
      • 标准上下文,是标准主机的子容器,Wrapper的父容器
    • StandardContextValve
      • 标准上下文阀门,运行逻辑向子容器流转
    • StandardWrapper
      • 标准包装器,是context的子容器
      • 其不再被允许添加子容器
    • StandardWrapperValve
      • 标准包装器阀门,运行逻辑向servlet规范流转

# tomcat设计--运行逻辑

# 请求的转换

/*xxx: 适配器,用于找到请求对应的 组件*/
public class CoyoteAdapter implements Adapter {
    @Override
    /*xxx: 可以看成tomcat的核心流程的处理起点 多线程环境*/
    public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
                throws Exception {
            /*xxx:1.根据Connector的请求和响应对象,创建Servlet请求和响应对象*/
            Request request = (Request) req.getNote(ADAPTER_NOTES);
            Response response = (Response) res.getNote(ADAPTER_NOTES);
            /*xxx: 传入的参数允许为空,为空时,则通过 连接器创建相应的request,response*/
            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().setQueryStringCharset(connector.getURICharset());
            }

            boolean postParseSuccess = false;
            /*xxx: 2.进行请求后置解析,转换请求参数,并完成请求映射, 该映射,是 tomcat层面的映射,比如 根据url映射到 host,context,wrapper等*/
            postParseSuccess = postParseRequest(req, request, res, response);

            //省略其它抽象...
     }
}

/*xxx: 连接器,对应于协议,用于 处理协议, 一个具有生命周期的组件*/
public class Connector extends LifecycleMBeanBase  {
    public Request createRequest() {
            return new Request(this);
    }
}

public class Request implements HttpServletRequest {
    public Request(Connector connector) {
       this.connector = connector;
       formats = new SimpleDateFormat[formatsTemplate.length];
       for(int i = 0; i < formats.length; i++) {
           formats[i] = (SimpleDateFormat) formatsTemplate[i].clone();
       }
    }
}

# 容器的映射

/*xxx: 适配器,用于找到请求对应的 组件*/
public class CoyoteAdapter implements Adapter {
    @Override
    /*xxx: 可以看成tomcat的核心流程的处理起点 多线程环境*/
    public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
                throws Exception {
        //省略其它抽象...
        boolean postParseSuccess = false;
        /*xxx: 2.进行请求后置解析,转换请求参数,并完成请求映射, 该映射,是 tomcat层面的映射,比如 根据url映射到 host,context,wrapper等*/
        postParseSuccess = postParseRequest(req, request, res, response);
        //省略其它抽象...
    }

    /*xxx: 后置解析请求方法*/
    /*xxx: 通过整个方法,tomcat确保得到的Context符合如下要求:
    *   匹配请求路径
    *   如果为有效会话,则包含会话的最新版本
    *   如没有有效会话,则为所有匹配请求的最新版本
    *   context必须是有效的(非暂停状态)*/
    protected boolean postParseRequest(org.apache.coyote.Request req, Request request,
            org.apache.coyote.Response res, Response response) throws IOException, ServletException {
        /*xxx: 请求RUI节码,初始化请求的路径参数*/
        MessageBytes undecodedURI = req.requestURI();
        // Check for ping OPTIONS * request
        if (undecodedURI.equals("*")) {
            /*xxx: 检测URI是否合法,如果非法,则返回响应码400*/
            if (req.method().equalsIgnoreCase("OPTIONS")) {
                StringBuilder allow = new StringBuilder();
                allow.append("GET, HEAD, POST, PUT, DELETE, OPTIONS");
                // Trace if allowed
                if (connector.getAllowTrace()) {
                    allow.append(", TRACE");
                }
                res.setHeader("Allow", allow.toString());
                // Access log entry as processing won't reach AccessLogValve
                connector.getService().getContainer().logAccess(request, response, 0, true);
                return false;
            } else {
                response.sendError(400, "Invalid URI");
            }
        }
         /*xxx:进行请求映射 */
         MessageBytes serverName;
         if (connector.getUseIPVHosts()) {
             serverName = req.localName();
             if (serverName.isNull()) {
                 // well, they did ask for it
                 res.action(ActionCode.REQ_LOCAL_NAME_ATTRIBUTE, null);
             }
         } else {
             serverName = req.serverName();
         }
         boolean mapRequired = true;
         while (mapRequired) {
             /*xxx: 通过绑定的service,进行映射, 映射规则为: 主机名,uri,servlet版本号,映射数据*/
             /*xxx: 请求映射处理最终 会根据 URI定位到 一个有效的 Wrapper, 该wrapper会处理好 request的映射信息*/
             connector.getService().getMapper().map(serverName, decodedURI,
                     version, request.getMappingData());
             if (request.getContext() == null) {
                 return true;
             }
             String sessionID;
             /*xxx: 这一步为 恢复SessionId */
             /*xxx: 无论是url中的session,还是 cookie中的session,最终都会 设置到当前 request中去 */
             /*xxx: 默认情况下,tracking-mode包括了两种形式,即 cookie  以及 url, 可以通过配置,动态配置相应特性*/
             if (request.getServletContext().getEffectiveSessionTrackingModes()
                     .contains(SessionTrackingMode.URL)) {
                    // Get the session ID if there was one
                 /*xxx: 获取servlet请求的session信息,从路径中获取,这是tomcat本身就支持的方式*/
                 sessionID = request.getPathParameter(
                         SessionConfig.getSessionUriParamName(
                                 request.getContext()));
                 if (sessionID != null) {
                     request.setRequestedSessionId(sessionID);
                     request.setRequestedSessionURL(true);
                 }
             }
                // Look for session ID in cookies and SSL session
             try {
                 /*xxx: 从cookie中以及 ssl上下文中,获取sessionId*/
                 parseSessionCookiesId(request);
             } catch (IllegalArgumentException e) {
                 // Too many cookies
                 if (!response.isError()) {
                     response.setError();
                     response.sendError(400);
                 }
                 return true;
             } 
             /*xxx: 最后,也可从 ssl中,恢复sessionId*/
             parseSessionSslId(request);
                /*xxx: 获取sessionId信息*/
             sessionID = request.getRequestedSessionId();
                mapRequired = false;
             if (version != null && request.getContext() == versionContext) {
                 // We got the version that we asked for. That is it.
             } else {
                 version = null;
                 versionContext = null;
                    Context[] contexts = request.getMappingData().contexts;
                 /*xxx: 因为同一个web应用,可能版本号不一致,因此要根据 sessionId首先去查找*/
                 if (contexts != null && sessionID != null) {
                     // Find the context associated with the session
                     for (int i = contexts.length; i > 0; i--) {
                         Context ctxt = contexts[i - 1];
                         /*xxx: 原生tomcat中,每个context都有一个 manager用于管理session*/
                         if (ctxt.getManager().findSession(sessionID) != null) {
                             if (!ctxt.equals(request.getMappingData().context)) {
                                 // Set version so second time through mapping
                                 // the correct context is found
                                 version = ctxt.getWebappVersion();
                                 versionContext = ctxt;
                                 // Reset mapping
                                 request.getMappingData().recycle();
                                 mapRequired = true;
                                 request.recycleSessionInfo();
                                 request.recycleCookieInfo(true);
                             }
                             break;
                         }
                     }
                 }
             }
                if (!mapRequired && request.getContext().getPaused()) {
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     // Should never happen
                 }
                 // Reset mapping
                 request.getMappingData().recycle();
                 mapRequired = true;
             }
         }
    }
}

/*xxx: 二级抽象: 用于维护 连接器 与 组件 的关系 ,多个 连接器(协议) 对应于一个 组件
*  xxx: 在这里,它的名称叫组件,实际上指的是 Engine,用于 处理请求
*   xxx: 在jvm中,对程序的执行,实际上 也是通过一个 Engine完成,它本质上是一个有限自动机*/
public interface Service extends Lifecycle {
    /*xxx:这个也是一个关键属性,映射器,用于请求查找*/
    Mapper getMapper();
}

/*xxx: 映射器,用于将请求与容器(host,context,Wrapper)进行映射*/
public final class Mapper {
    public void map(MessageBytes host, MessageBytes uri, String version,
                        MappingData mappingData) throws IOException {
    
        if (host.isNull()) {
            String defaultHostName = this.defaultHostName;
            if (defaultHostName == null) {
                return;
            }
            host.getCharChunk().append(defaultHostName);
        }
        host.toChars();
        uri.toChars();
        /*xxx: 内部映射*/
        internalMap(host.getCharChunk(), uri.getCharChunk(), version, mappingData);
    }

    private final void internalMap(CharChunk host, CharChunk uri,
                String version, MappingData mappingData) throws IOException {
         if (mappingData.host != null) {
            throw new AssertionError();
        }
         // Virtual host mapping
        MappedHost[] hosts = this.hosts;
        /*xxx: 找到虚拟主机*/
        MappedHost mappedHost = exactFindIgnoreCase(hosts, host);
        if (mappedHost == null) {
            int firstDot = host.indexOf('.');
            if (firstDot > -1) {
                int offset = host.getOffset();
                try {
                    host.setOffset(firstDot + offset);
                    mappedHost = exactFindIgnoreCase(hosts, host);
                } finally {
                    // Make absolutely sure this gets reset
                    host.setOffset(offset);
                }
            }
            if (mappedHost == null) {
                mappedHost = defaultHost;
                if (mappedHost == null) {
                    return;
                }
            }
        }
        mappingData.host = mappedHost.object;
         if (uri.isNull()) {
            // Can't map context or wrapper without a uri
            return;
        }
         uri.setLimit(-1);
         // Context mapping
        /*xxx: 根据uri进行 应用映射*/
        ContextList contextList = mappedHost.contextList;
        MappedContext[] contexts = contextList.contexts;
        int pos = find(contexts, uri);
        if (pos == -1) {
            return;
        }
         int lastSlash = -1;
        int uriEnd = uri.getEnd();
        int length = -1;
        boolean found = false;
        MappedContext context = null;
        while (pos >= 0) {
            context = contexts[pos];
            if (uri.startsWith(context.name)) {
                length = context.name.length();
                if (uri.getLength() == length) {
                    found = true;
                    break;
                } else if (uri.startsWithIgnoreCase("/", length)) {
                    found = true;
                    break;
                }
            }
            if (lastSlash == -1) {
                lastSlash = nthSlash(uri, contextList.nesting + 1);
            } else {
                lastSlash = lastSlash(uri);
            }
            uri.setEnd(lastSlash);
            pos = find(contexts, uri);
        }
        uri.setEnd(uriEnd);
         if (!found) {
            if (contexts[0].name.equals("")) {
                context = contexts[0];
            } else {
                context = null;
            }
        }
        if (context == null) {
            return;
        }
         mappingData.contextPath.setString(context.name);
         ContextVersion contextVersion = null;
        ContextVersion[] contextVersions = context.versions;
        final int versionCount = contextVersions.length;
        if (versionCount > 1) {
            Context[] contextObjects = new Context[contextVersions.length];
            for (int i = 0; i < contextObjects.length; i++) {
                contextObjects[i] = contextVersions[i].object;
            }
            mappingData.contexts = contextObjects;
            if (version != null) {
                contextVersion = exactFind(contextVersions, version);
            }
        }
        if (contextVersion == null) {
            contextVersion = contextVersions[versionCount - 1];
        }
        mappingData.context = contextVersion.object;
        mappingData.contextSlashCount = contextVersion.slashCount;
         // Wrapper mapping
        /*xxx: 最后进行 servlet的映射查找*/
        if (!contextVersion.isPaused()) {
            internalMapWrapper(contextVersion, uri, mappingData);
        }
     }

    private final void internalMapWrapper(ContextVersion contextVersion,
                                              CharChunk path,
                                              MappingData mappingData) throws IOException {
        int pathOffset = path.getOffset();
        int pathEnd = path.getEnd();
        boolean noServletPath = false;
         int length = contextVersion.path.length();
        if (length == (pathEnd - pathOffset)) {
            noServletPath = true;
        }
        int servletPath = pathOffset + length;
        path.setOffset(servletPath);
        /*xxx: 首先,进行精确匹配*/
        MappedWrapper[] exactWrappers = contextVersion.exactWrappers;
        internalMapExactWrapper(exactWrappers, path, mappingData);
        /*xxx: 其次,进行前缀匹配*/
        boolean checkJspWelcomeFiles = false;
        MappedWrapper[] wildcardWrappers = contextVersion.wildcardWrappers;
        if (mappingData.wrapper == null) {
            internalMapWildcardWrapper(wildcardWrappers, contextVersion.nesting,
                                       path, mappingData);
            if (mappingData.wrapper != null && mappingData.jspWildCard) {
                char[] buf = path.getBuffer();
                if (buf[pathEnd - 1] == '/') {
                    mappingData.wrapper = null;
                    checkJspWelcomeFiles = true;
                } else {
                    // See Bugzilla 27704
                    mappingData.wrapperPath.setChars(buf, path.getStart(),
                                                     path.getLength());
                    mappingData.pathInfo.recycle();
                }
            }
        }
         if(mappingData.wrapper == null && noServletPath &&
                contextVersion.object.getMapperContextRootRedirectEnabled()) {
            // The path is empty, redirect to "/"
            path.append('/');
            pathEnd = path.getEnd();
            mappingData.redirectPath.setChars
                (path.getBuffer(), pathOffset, pathEnd - pathOffset);
            path.setEnd(pathEnd - 1);
            return;
        }
        /*xxx: 然后,进行 扩展名 匹配*/
        MappedWrapper[] extensionWrappers = contextVersion.extensionWrappers;
        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
            internalMapExtensionWrapper(extensionWrappers, path, mappingData,
                    true);
        }
         // Rule 4 -- Welcome resources processing for servlets
        /*xxx: 然后,进行欢迎资源处理的servlet映射*/
        if (mappingData.wrapper == null) {
            boolean checkWelcomeFiles = checkJspWelcomeFiles;
            if (!checkWelcomeFiles) {
                char[] buf = path.getBuffer();
                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
            }
            if (checkWelcomeFiles) {
                for (int i = 0; (i < contextVersion.welcomeResources.length)
                         && (mappingData.wrapper == null); i++) {
                    path.setOffset(pathOffset);
                    path.setEnd(pathEnd);
                    path.append(contextVersion.welcomeResources[i], 0,
                            contextVersion.welcomeResources[i].length());
                    path.setOffset(servletPath);
                     // Rule 4a -- Welcome resources processing for exact macth
                    internalMapExactWrapper(exactWrappers, path, mappingData);
                     // Rule 4b -- Welcome resources processing for prefix match
                    if (mappingData.wrapper == null) {
                        internalMapWildcardWrapper
                            (wildcardWrappers, contextVersion.nesting,
                             path, mappingData);
                    }
                     // Rule 4c -- Welcome resources processing
                    //            for physical folder
                    if (mappingData.wrapper == null
                        && contextVersion.resources != null) {
                        String pathStr = path.toString();
                        WebResource file =
                                contextVersion.resources.getResource(pathStr);
                        if (file != null && file.isFile()) {
                            internalMapExtensionWrapper(extensionWrappers, path,
                                                        mappingData, true);
                            if (mappingData.wrapper == null
                                && contextVersion.defaultWrapper != null) {
                                mappingData.wrapper =
                                    contextVersion.defaultWrapper.object;
                                mappingData.requestPath.setChars
                                    (path.getBuffer(), path.getStart(),
                                     path.getLength());
                                mappingData.wrapperPath.setChars
                                    (path.getBuffer(), path.getStart(),
                                     path.getLength());
                                mappingData.requestPath.setString(pathStr);
                                mappingData.wrapperPath.setString(pathStr);
                            }
                        }
                    }
                }
                 path.setOffset(servletPath);
                path.setEnd(pathEnd);
            }
         }
        if (mappingData.wrapper == null) {
            boolean checkWelcomeFiles = checkJspWelcomeFiles;
            if (!checkWelcomeFiles) {
                char[] buf = path.getBuffer();
                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
            }
            if (checkWelcomeFiles) {
                for (int i = 0; (i < contextVersion.welcomeResources.length)
                         && (mappingData.wrapper == null); i++) {
                    path.setOffset(pathOffset);
                    path.setEnd(pathEnd);
                    path.append(contextVersion.welcomeResources[i], 0,
                                contextVersion.welcomeResources[i].length());
                    path.setOffset(servletPath);
                    internalMapExtensionWrapper(extensionWrappers, path,
                                                mappingData, false);
                }
                 path.setOffset(servletPath);
                path.setEnd(pathEnd);
            }
        }
          // Rule 7 -- Default servlet
        /*xxx: 最后,采用 默认的servlet*/
        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
            if (contextVersion.defaultWrapper != null) {
                mappingData.wrapper = contextVersion.defaultWrapper.object;
                mappingData.requestPath.setChars
                    (path.getBuffer(), path.getStart(), path.getLength());
                mappingData.wrapperPath.setChars
                    (path.getBuffer(), path.getStart(), path.getLength());
                mappingData.matchType = MappingMatch.DEFAULT;
            }
            // Redirection to a folder
            char[] buf = path.getBuffer();
            if (contextVersion.resources != null && buf[pathEnd -1 ] != '/') {
                String pathStr = path.toString();
                if (contextVersion.object.getMapperDirectoryRedirectEnabled()) {
                    WebResource file;
                    // Handle context root
                    if (pathStr.length() == 0) {
                        file = contextVersion.resources.getResource("/");
                    } else {
                        file = contextVersion.resources.getResource(pathStr);
                    }
                    if (file != null && file.isDirectory()) {
                        path.setOffset(pathOffset);
                        path.append('/');
                        mappingData.redirectPath.setChars
                            (path.getBuffer(), path.getStart(), path.getLength());
                    } else {
                        mappingData.requestPath.setString(pathStr);
                        mappingData.wrapperPath.setString(pathStr);
                    }
                } else {
                    mappingData.requestPath.setString(pathStr);
                    mappingData.wrapperPath.setString(pathStr);
                }
            }
        }
         path.setOffset(pathOffset);
        path.setEnd(pathEnd);
    }
}

# Valve如何流转

  • 标准Valve流转 ---流转至子容器的Pipeline的第一个valve
final class StandardEngineValve extends ValveBase {
    @Override
    public final void invoke(Request request, Response response)
            throws IOException, ServletException {
        /*xxx: 在连接器阶段,已经将请求所需要对应的host进行了映射*/
        /*xxx: 如果当前的容器没有设置 host,则也会报404错误, 是tomcat容器层面报的*/
        Host host = request.getHost();
        host.getPipeline().getFirst().invoke(request, response);
    }
}

final class StandardHostValve extends ValveBase {
    @Override
    public final void invoke(Request request, Response response)
            throws IOException, ServletException {
        /*xxx: 从请求中获取 context容器 , 在连接器阶段,已经将该请求,所需要使用到的容器进行了映射*/
        Context context = request.getContext();
        context.getPipeline().getFirst().invoke(request, response);
    }
}

final class StandardContextValve extends ValveBase {
    @Override
    public final void invoke(Request request, Response response)
            throws IOException, ServletException {
        /*xxx: 如果没有与当前请求相匹配的Wrapper,也会报错*/
        Wrapper wrapper = request.getWrapper();
        if (wrapper == null || wrapper.isUnavailable()) {
             response.sendError(HttpServletResponse.SC_NOT_FOUND);
             return;
        }
        wrapper.getPipeline().getFirst().invoke(request, response);
    }
}

final class StandardWrapperValve
    extends ValveBase {
    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        Servlet servlet = null;
        long available = wrapper.getAvailable();
        if (!unavailable) {
            /*xxx: 默认的 servlet从这个方法而来*/
            servlet = wrapper.allocate();
        }
        /*xxx: 从这里,开始进入 Servlet规范,进行处理*/
        ApplicationFilterChain filterChain =
                        ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
        if ((servlet != null) && (filterChain != null)) {
            filterChain.doFilter(request.getRequest(), response.getResponse());
        }
    }
}
  • 普通Valve流转--流转至本容器的下一个valve
public class ErrorReportValve extends ValveBase {
    @Override
    public void invoke(Request request, Response response) throws IOException, ServletException {
        getNext().invoke(request, response);
        //省略其他抽象...
    }
}

public final class JDBCAccessLogValve extends ValveBase implements AccessLog {
    @Override
    public void invoke(Request request, Response response) throws IOException,
            ServletException {
        getNext().invoke(request, response);
    }
}
  • 可以得出结论,标准valve总是位于pipeline的最后一个valve

# 最佳实践--常见模型

# service与映射器

  • service层面的映射器,将当前请求对应的host,context,wrapper进行映射;
  • 具体的映射过程,见上文运行逻辑-容器映射部分源码;

# container与pipeline

  • 每个容器组件,都具有一个pipeline
  • pipeline用于存放valve
  • valve具有两类,标准valve,以及普通valve,具体的区别见上文运行逻辑-valve如何流转部分源码;

# context与管理器

  • 原生tomcat环境下,管理器Manager,用于管理session,包括生成session,管理session,移除session等;
  • 常用实现为: StandardManager
  • 抽象模型
public interface Manager {
    /*xxx: id生成器 */
    public SessionIdGenerator getSessionIdGenerator();

    /*xxx: 创建session */
    public Session createSession(String sessionId);

    /*xxx: 添加session */
    public void add(Session session);
}

public abstract class ManagerBase extends LifecycleMBeanBase implements Manager {

    /*xxx: 在该 StandardManager中,对sessionId 与 Session进行了缓存, 结果缓存在内存中的*/
    protected Map<String, Session> sessions = new ConcurrentHashMap<>();
    
    protected SessionIdGenerator sessionIdGenerator = null;
    protected Class<? extends SessionIdGenerator> sessionIdGeneratorClass = null;

    @Override
    public Session createSession(String sessionId) {
       if ((maxActiveSessions >= 0) &&
               (getActiveSessions() >= maxActiveSessions)) {
           rejectedSessions++;
           throw new TooManyActiveSessionsException(
                   sm.getString("managerBase.createSession.ise"),
                   maxActiveSessions);
       }
       // Recycle or create a Session instance
       Session session = createEmptySession();
       // Initialize the properties of the new session and return it
       session.setNew(true);
       session.setValid(true);
       session.setCreationTime(System.currentTimeMillis());
       /*xxx: 设置新创建的session的超时时间 */
       session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);
       String id = sessionId;
       if (id == null) {
           id = generateSessionId();
       }
       session.setId(id);
       sessionCounter++;
       SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
       synchronized (sessionCreationTiming) {
           sessionCreationTiming.add(timing);
           sessionCreationTiming.poll();
       }
       return session;
    }

    @Override
    public SessionIdGenerator getSessionIdGenerator() {
        if (sessionIdGenerator != null) {
            return sessionIdGenerator;
        } else if (sessionIdGeneratorClass != null) {
            try {
                sessionIdGenerator = sessionIdGeneratorClass.getConstructor().newInstance();
                return sessionIdGenerator;
            } catch(ReflectiveOperationException ex) {
                // Ignore
            }
        }
        return null;
    }

    @Override
    /*xxx: 每次添加的时候,会进行最大session量的控制,超过后,则阻塞*/
    public void add(Session session) {
        sessions.put(session.getIdInternal(), session);
        int size = getActiveSessions();
        if( size > maxActive ) {
            synchronized(maxActiveUpdateLock) {
                if( size > maxActive ) {
                    maxActive = size;
                }
            }
        }
    }
}

# 原生tomcat的session的生成逻辑

  • 从cookie或者url中恢复sessionId(再根据sessionId恢复)
  • 或者从request创建,并写入到response的cookie中(允许使用cookie的话)
//package org.apache.catalina.connector;
public class Request implements HttpServletRequest {

    protected Session session = null;

    protected org.apache.catalina.connector.Response response = null;

    @Override
    public HttpSession getSession(boolean create) {
        Session session = doGetSession(create);
        if (session == null) {
            return null;
        }
         return session.getSession();
    }
    
    protected Session doGetSession(boolean create) {
    
      Context context = getContext();
      if (context == null) {
          return null;
      }
      // Return the current session if it exists and is valid
      if ((session != null) && !session.isValid()) {
          session = null;
      }
      /*xxx: 如果之前已经获取过session,并且session是合法的,则直接返回*/
      if (session != null) {
          return session;
      }
      /*xxx: StandardManager实例是从 context中获取的,换言之,session是存在内存中的,并且以Context为单位进行隔离*/
      Manager manager = context.getManager();
      if (manager == null) {
          return null;      // Sessions are not supported
      }
      if (requestedSessionId != null) {
          try {
              /*xxx: 获取session,实际上是根据 coyoteAdaptor阶段,恢复的sessionId,通过该Session去 Manager中,寻找与之映射的 session实例 */
              session = manager.findSession(requestedSessionId);
          } catch (IOException e) {
              session = null;
          }
          if ((session != null) && !session.isValid()) {
              session = null;
          }
          if (session != null) {
              /*xxx: 刷新session的最近访问时间*/
              session.access();
              return session;
          }
      }
      // Create a new session if requested and the response is not committed
      if (!create) {
          return null;
      }
      /*xxx: session的创建逻辑 */
      boolean trackModesIncludesCookie =
              context.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE);
      if (trackModesIncludesCookie && response.getResponse().isCommitted()) {
          throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted"));
      }
      String sessionId = getRequestedSessionId();
      if (requestedSessionSSL) {
          // If the session ID has been obtained from the SSL handshake then
          // use it.
      } else if (("/".equals(context.getSessionCookiePath())
              && isRequestedSessionIdFromCookie())) {
          if (context.getValidateClientProvidedNewSessionId()) {
              boolean found = false;
              for (Container container : getHost().findChildren()) {
                  Manager m = ((Context) container).getManager();
                  if (m != null) {
                      try {
                          if (m.findSession(sessionId) != null) {
                              found = true;
                              break;
                          }
                      } catch (IOException e) {
                      }
                  }
              }
              if (!found) {
                  sessionId = null;
              }
          }
      } else {
          sessionId = null;
      }
      /*xxx: session的创建,最终是通过 session管理器完成的。 */
      session = manager.createSession(sessionId);
      /*xxx: 当创建session成功后,同时会将当前的session,写入到 response头部中 */
      if (session != null && trackModesIncludesCookie) {
          Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie(
                  context, session.getIdInternal(), isSecure());
          response.addSessionCookieInternal(cookie);
      }
      if (session == null) {
          return null;
      }
      session.access();
      return session;
    }
}

# ApplicationContext上下文(cataina)

  • 抽象结构
//package javax.servlet;
public interface ServletContext {
    /*xxx: 获取资源*/
    public URL getResource(String path) throws MalformedURLException;    

    /*xxx: 获取请求分发器*/
    public RequestDispatcher getRequestDispatcher(String path);

    /*xxx: 获取初始化参数名称枚举对象*/
    public Enumeration<String> getInitParameterNames();

    /*xxx: 添加servlet*/
    public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet);

    /*xxx: 获取servlet注册表*/
    public ServletRegistration getServletRegistration(String servletName);

    /*xxx: 添加过滤器*/
    public FilterRegistration.Dynamic addFilter(String filterName, String className);

    /*xxx: 获取过滤器注册表*/
    public FilterRegistration getFilterRegistration(String filterName);

    /*xxx: 获取session配置信息*/
    public SessionCookieConfig getSessionCookieConfig();

    /*xxx: 添加监听器 */
    public void addListener(Class<? extends EventListener> listenerClass);

    /*xxx: 根据uri,获取servletContext上下文对象 */
    public ServletContext getContext(String uripath);

}

/*xxx:应用上下文,实现了servlet的上下文规范*/
public class ApplicationContext implements ServletContext {

    private final StandardContext context;

    private final Service service;    

    private SessionCookieConfig sessionCookieConfig;

     public ApplicationContext(StandardContext context) {
       super();
       this.context = context;
       this.service = ((Engine) context.getParent().getParent()).getService();
       this.sessionCookieConfig = new ApplicationSessionCookieConfig(context);
       // Populate session tracking modes
       /*xxx: 填充session的 track-mode ,如果没有,则用默认的。  默认包含了两种  即 url 和 cookie */
       populateSessionTrackingModes();
     }
}
  • 应用实例
public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {

    /*xxx: 应用上下文,是servletContext的直接子类,其为 protected属性*/
    protected ApplicationContext context = null;    

    @Override
    public ServletContext getServletContext() {
        if (context == null) {
            context = new ApplicationContext(this);
            if (altDDName != null)
                context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
        }
        return context.getFacade();
    }
}

# ServletContext

  • 抽象结构
    • 见上文,ApplicationContext上下文(cataina)
  • 如何获取资源;
public interface ServletContext {
    /*xxx: 获取资源*/
    public URL getResource(String path) throws MalformedURLException;
}

/*xxx:应用上下文,实现了servlet的上下文规范*/
public class ApplicationContext implements ServletContext {

    private final StandardContext context;

    @Override
    public URL getResource(String path) throws MalformedURLException {
         String validatedPath = validateResourcePath(path, false);
         if (validatedPath == null) {
            throw new MalformedURLException(
                    sm.getString("applicationContext.requestDispatcher.iae", path));
        }
         WebResourceRoot resources = context.getResources();
        if (resources != null) {
            return resources.getResource(validatedPath).getURL();
        }
         return null;
    }
}

public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {
    
    private WebResourceRoot resources;

    @Override
    public WebResourceRoot getResources() {
        Lock readLock = resourcesLock.readLock();
        readLock.lock();
        try {
            return resources;
        } finally {
            readLock.unlock();
        }
    }
}
        
public interface WebResourceRoot extends Lifecycle {

    /*xxx: 根据路径获取web资源 */
    WebResource getResource(String path);

    /*xxx: 添加pre类型的资源*/
    void addPreResources(WebResourceSet webResourceSet);

    /*xxx: 添加jar类型资源*/
    void addJarResources(WebResourceSet webResourceSet);

    /*xxx: 添加post类型资源*/
    void addPostResources(WebResourceSet webResourceSet);

    /*xxx: 资源类型*/
    enum ResourceSetType {
        PRE,
        RESOURCE_JAR,
        POST,
        CLASSES_JAR
    }
}

public class StandardRoot extends LifecycleMBeanBase implements WebResourceRoot {
    private final Cache cache = new Cache(this);

    private WebResourceSet main;

    @Override
    protected void startInternal() throws LifecycleException {
        main = createMainResourceSet();
    }

    protected WebResourceSet createMainResourceSet() {
       String docBase = context.getDocBase();
       WebResourceSet mainResourceSet;
       if (docBase == null) {
           mainResourceSet = new EmptyResourceSet(this);
       } else {
           File f = new File(docBase);
           if (!f.isAbsolute()) {
               f = new File(((Host)context.getParent()).getAppBaseFile(), f.getPath());
           }
           if (f.isDirectory()) {
               mainResourceSet = new DirResourceSet(this, "/", f.getAbsolutePath(), "/");
           } else if(f.isFile() && docBase.endsWith(".war")) {
               mainResourceSet = new WarResourceSet(this, "/", f.getAbsolutePath());
           } else {
               throw new IllegalArgumentException(
                       sm.getString("standardRoot.startInvalidMain",
                               f.getAbsolutePath()));
           }
       }
       return mainResourceSet;
    }

    @Override
    public WebResource getResource(String path) {
        return getResource(path, true, false);
    }

    protected WebResource getResource(String path, boolean validate,
            boolean useClassLoaderResources) {
        if (validate) {
            path = validate(path);
        }
         if (isCachingAllowed()) {
            return cache.getResource(path, useClassLoaderResources);
        } else {
            return getResourceInternal(path, useClassLoaderResources);
        }
    }

    /*xxx: 实际获取资源的方法 */
    protected final WebResource getResourceInternal(String path,
           boolean useClassLoaderResources) {
       WebResource result = null;
       WebResource virtual = null;
       WebResource mainEmpty = null;
       /*xxx: 从 preResource,jarReosurce,postResource,mainResource,classResource中获取资源 */
       for (List<WebResourceSet> list : allResources) {
           for (WebResourceSet webResourceSet : list) {
               if (!useClassLoaderResources &&  !webResourceSet.getClassLoaderOnly() ||
                       useClassLoaderResources && !webResourceSet.getStaticOnly()) {
                   result = webResourceSet.getResource(path);
                   /*xxx: 获取到资源,则直接返回*/
                   if (result.exists()) {
                       return result;
                   }
                   /*xxx: 没获取到资源*/
                   if (virtual == null) {
                       /*xxx: 看是否是虚拟资源*/
                       if (result.isVirtual()) {
                           virtual = result;
                       } else if (main.equals(webResourceSet)) {
                           mainEmpty = result;
                       }
                   }
               }
           }
       }
       // Use the first virtual result if no real result was found
       if (virtual != null) {
           return virtual;
       }
       // Default is empty resource in main resources
       return mainEmpty;
    }
}

public interface WebResourceSet extends Lifecycle {
    /*xxx: 根据路径获取资源 */
    WebResource getResource(String path);
}

public class FileResourceSet extends AbstractFileResourceSet {
}

public class DirResourceSet extends AbstractFileResourceSet {
}

public class WarResourceSet extends AbstractSingleArchiveResourceSet {
}
  • 与WEB-INF的关系
    • 由源码中得知,WEB-INF 与资源并无直接关系,而是通过 context的docBase决定的资源位置;
    • 但是WEB-INF确实有其特殊性,它是war包打包规范中的一个默认路径;

# ApplicationFilterChain原生过滤链

  • 原生过滤链的构建
final class StandardWrapperValve
    extends ValveBase {

    /*xxx: 一个合法的 wrapper,包含一个 servlet*/
    /*xxx: 服务器轻量级程序,在service的映射器时,已经将本次请求的wrapper与相应的servlet进行了映射 */
    Servlet servlet = null;
    
    @Override
    public final void invoke(Request request, Response response)
            throws IOException, ServletException {
        /*xxx: 默认的 servlet从这个方法而来*/
        servlet = wrapper.allocate();

        /*xxx: 从这里,开始进入 Servlet规范,进行处理*/
        /*xxx: 过滤链的构建,由过滤链构造器完成 */
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

        /*xxx: 通过原生过滤链的过滤操作,完成 servlet的功能*/
        filterChain.doFilter(request.getRequest(),
                response.getResponse());
        
        //xxx: 最后,会进行 filterChain的释放,servlet的卸载等等操作
    }
}

/*xxx: 过滤链构造器,由tomcat提供 */
public final class ApplicationFilterFactory {
    /*xxx: 创建过滤链 */
    public static ApplicationFilterChain createFilterChain(ServletRequest request,
                                                           Wrapper wrapper, Servlet servlet) {
        /*xxx: 创建过滤链必须有指定的servlet,否则返空 */
        if (servlet == null)
            return null;
        /*xxx: 原生过滤链 */
        ApplicationFilterChain filterChain = null;
        if (request instanceof Request) {
            Request req = (Request) request;
            /*xxx: 从请求中,获取过滤链, 没有则 进行设置  */
            filterChain = (ApplicationFilterChain) req.getFilterChain();
            if (filterChain == null) {
                filterChain = new ApplicationFilterChain();
                req.setFilterChain(filterChain);
            }
        }else{
            /*xxx: 分发器使用时,则直接实例化 */
            filterChain = new ApplicationFilterChain();
        }
        filterChain.setServlet(servlet);

        /*xxx: 从上下文中,获取 过滤器注册表 */
        FilterMap filterMaps[] = context.findFilterMaps();

        if ((filterMaps == null) || (filterMaps.length == 0))
            return filterChain;

        /*xxx: 根据请求的路径,决定需要经过过滤器过滤组件 */
        for (FilterMap filterMap : filterMaps) {
            /*xxx: 首先进行分发模式匹配,包括 forward,include,request,error,async */
            if (!matchDispatcher(filterMap, dispatcher)) {
                continue;
            }
            /*xxx: 其次进行url匹配,包括全匹配,模式匹配,扩展名匹配*/
            if (!matchFiltersURL(filterMap, requestPath))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                    context.findFilterConfig(filterMap.getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            /*xxx: 加入过滤器 */
            filterChain.addFilter(filterConfig);
        }

        // Add filters that match on servlet name second
        /*xxx: 根据servlet的名称,筛选需要过滤的过滤器*/
        for (FilterMap filterMap : filterMaps) {
            if (!matchDispatcher(filterMap, dispatcher)) {
                continue;
            }
            /*xxx: 特定servlet 名称的过滤器 */
            if (!matchFiltersServlet(filterMap, servletName))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                    context.findFilterConfig(filterMap.getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // Return the completed filter chain
        return filterChain;
    }
}
  • 原生过滤链过滤器的流转 以及 与servlet的流转
/*xxx: servlet规范 中 原生filterChain接口 */
/*xxx: springSecurity主要就是基于该标准的扩展,在原生的应用级过滤链上面,新增虚拟过滤链*/
public interface FilterChain {
    
    /*xxx: 进行过滤动作 */
    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;
    
}

/*xxx: 应用过滤器,由tomcat 实现的servlet 过滤器规范   */
public final class ApplicationFilterChain implements FilterChain {

    /*xxx: 当前过滤链过滤器的个数*/
    private int n = 0;

    /*xxx: 当前过滤链过滤的位置,过滤链与上过滤器的推进,全靠这个参数 */
    /*xxx: 通过这个参数,各过滤器的执行可以完成类似出入栈的递归结构*/
    /*xxx: 在某个过滤器没有调用过滤链的迭代方法时,又可完成水平迭代的功能*/
    private int pos = 0;

    /*xxx: 应用过滤器配置信息数组,存储了所有的原生过滤器  */
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    
    @Override
    /*xxx: 进行过滤动作  */
    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException {
        //xxx: 省略其他抽象...
        internalDoFilter(req,res);
    }

    /*xxx: 实际过滤动作 */
    private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
            throws IOException, ServletException {
        if (pos < n) {
            /*xxx: 从原生过滤器配置信息 数组中进行迭代  */
            ApplicationFilterConfig filterConfig = filters[pos++];
            /*xxx: 根据过滤器配置信息,获取实际的过滤器实例  */
            Filter filter = filterConfig.getFilter();
            /*xxx: 根据获取到的过滤器  执行 过滤,并将当前的 过滤器实例作为参数传入 */
            filter.doFilter(request, response, this);
        }
        /*xxx: 当原生过滤链执行完毕后,就会执行servlet的service方法*/
        /*xxx: filter 到 servlet 的流转,是通过 过滤链完成的*/
        servlet.service(request, response);
    }
    
    //xxx: 省略其他抽象...
}

# ApplicationDispatcher应用分发器

  • 应用分发器的构造逻辑
public interface ServletContext {
    /*xxx: 获取请求分发器*/
    public RequestDispatcher getRequestDispatcher(String path);
}

/*xxx:应用上下文,实现了servlet的上下文规范*/
public class ApplicationContext implements ServletContext {
    @Override
    public RequestDispatcher getRequestDispatcher(final String path) {
        /*xxx: 通过映射器去查找 wrapper */
        service.getMapper().map(context, uriMB, mappingData);

        /*xxx: 通过映射器的映射结果,来实例化新的 应用分发器 */
        return new ApplicationDispatcher(wrapper, uri, wrapperPath, pathInfo,
                queryString, mapping, null);
    }
}
  • 应用分发器的流转逻辑
public interface RequestDispatcher {
    /*xxx: 重定向 */
    public void forward(ServletRequest request, ServletResponse response)
            throws ServletException, IOException;
}

public interface AsyncDispatcher {
    /*xxx: 异步分发*/
    public void dispatch(ServletRequest request, ServletResponse response)
            throws ServletException, IOException;
}

final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher {
    
    /*xxx: 异步分发*/
    private void doDispatch(ServletRequest request, ServletResponse response)
            throws ServletException, IOException {
        State state = new State(request, response, false);
        invoke(state.outerRequest, state.outerResponse, state);
    }

    private void invoke(ServletRequest request, ServletResponse response,
                        State state) throws IOException, ServletException {
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
        filterChain.doFilter(request, response);
    }

    private void doForward(ServletRequest request, ServletResponse response)
            throws ServletException, IOException
    {
        State state = new State(request, response, false);
        processRequest(request,response,state);
    }

    private void processRequest(ServletRequest request,
                                ServletResponse response,
                                State state)
            throws IOException, ServletException {
        invoke(state.outerRequest, response, state);
    }
}

# 最佳实践--解析JSP视图

# 添加jspServlet,并指定名称

  • springBoot项目需要依赖项目: embbed-tomcat-jasper,该项目中包含了 JspServlet,包含了该类,embbed-tomcat启动时,才会自动装载;
  • spring项目,默认tomcat容器已经包含了JspServlet所在的模块,并自动将之装载了,以 jsp为名;

# 调用jsp的service方法,获取jsp方法执行渲染

  • jsp的service方法,会使用访问者模式,进行元素节点的渲染;具体过程略

# 最佳实践--springMvc的结合

# xml方式如何对DispatcherServlet进行装载

/*xxx: 在标准的catalina容器启动过程中,会为上下文默认添加一个生命周期监听器  --- contextConfig*/
    /*xxx: 它将会处理六个事件,核心事件由三个: AFTER_INIT_EVENT,
       BEFORE_START_EVENT,
       CONFIGURE_START_EVENT*/
public class ContextConfig implements LifecycleListener {
    
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
            /*xxx: 通过该事件,解析web.xml,创建 Wrapper包装器,过滤器,上下文监听器 的鞥一系列容器相关的对象,完成容器的初始化*/
            configureStart();
        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
            /*xxx: 该事件在 Context启动之前触发, 用于更新 context的docBase属性和解决  web目录锁的问题*/
            beforeStart();
        } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
            // Restore docBase for management tools
            if (originalDocBase != null) {
                context.setDocBase(originalDocBase);
            }
        }else{
            //xxx: 省略其他抽象...
        }
    }

    protected synchronized void configureStart() {
        /*xxx: 根据配置创建包装器,过滤器,监听器,  除了解析web.xml,还包括 tomcat默认配置,web-fragment.xml,ServletContainerInitializer,以及相关xml文件的排序和合并*/
        webConfig();

        if (!context.getIgnoreAnnotations()) {
            /*xxx: 若 标准上下文的ignoreAnnotations为false,则解析应用程序注解配置,添加相关的JNDI资源引用*/
            applicationAnnotationsConfig();
        }
    }

    protected void webConfig() {
        /*xxx: 1.解析默认配置,生成web.xml对象
         *  从上述代码看出,先解析容器级配置(config/web.xml),
         *  再解析 host级配置,对于同名配置,host级将覆盖容器级,为了提高性能,会对容器级配置进行缓存,避免重复解析*/
        WebXml webXml = createWebXml();

        /*xxx: 2.解析web应用的wb.xml文件配置,  注意 StandardContext的 'org.apache.catalina.deploy.alt_dd'属性,用于指定web.xml路径,如未指定,则使用默认的 WEB-INF/web.xml*/
        InputSource contextWebXml = getContextWebXmlSource();

        /*xxx: 3.扫描web应用所有的jar包,如果含有 META-INF/web-fragment.xml,则解析,并创建webXml对象*/
        Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);

        /*xxx: 4.将 web-fragment.xml创建的WebXml对象按照Servlet规范进行排序,同时将对相应的结果设置到 ServletContext属性中*/
        orderedFragments =
                WebXml.orderWebFragments(webXml, fragments, sContext);

        /*xxx: 5.查找ServletContainerInitializer实现,并创建实例,查找范围分为两部分:
         *  web应用下的包: 如果上下文中属性:javax.servlet.conetxt.orderedLibs不为空,则仅搜索包含的包,否则搜索WEB-INF/lib下的所有包
         *  容器包: 搜索所有包
         *  容器包中的实现,将优先加载*/
        /*xxx: 6.根据 servletContainerInitializer的结果,以及相应的  javax.servlet.annotaion.HandlesTypes注解配置,维护Initializer映射*/
        processServletContainerInitializers();

        /*xxx: 7.处理WEB-INF/classess下的注解,以及含有 web-fragment.xml的jar中的注解,然后进行合并*/
        processClasses(webXml, orderedFragments);

        /*xxx:10.对于web应用中 JspFile属性不为空的Servlet,将其 servletClass设为 org.apache.jasper.servelt.JspServlet*/
        convertJsps(webXml);

        /*xxx: 查找 含有 web-fragment.xml的jar包 “META-INF/resources/”下的静态资源,并添加到StandardContext*/
        Set<WebXml> resourceJars = new LinkedHashSet<>(orderedFragments);
        for (WebXml fragment : fragments.values()) {
            if (!resourceJars.contains(fragment)) {
                resourceJars.add(fragment);
            }
        }

        /*xxx: 将xml配置信息,应用于上下文中,也是最重要的一步*/
        configureContext(webXml);
    }

    private void configureContext(WebXml webxml) {
        /*xxx: 遍历 配置过滤器 */
        for (FilterDef filter : webxml.getFilters().values()) {
            if (filter.getAsyncSupported() == null) {
                filter.setAsyncSupported("false");
            }
            context.addFilterDef(filter);
        }
        /*xxx: 遍历配置过滤器映射信息,包括servlet名称映射(*代表所有servlet),路径映射(路径用的更多) */
        for (FilterMap filterMap : webxml.getFilterMappings()) {
            context.addFilterMap(filterMap);
        }

        /*xxx: 遍历添加监听器信息 */
        for (String listener : webxml.getListeners()) {
            context.addApplicationListener(listener);
        }

        /*xxx: 遍历取出 servlet,并将之包装成 wrapper */
        for (ServletDef servlet : webxml.getServlets().values()) {
            Wrapper wrapper = context.createWrapper();
            /*xxx: wrapper的名字,就是servlet 的名字 */
            wrapper.setName(servlet.getServletName());

            Map<String,String> params = servlet.getParameterMap();
            for (Entry<String, String> entry : params.entrySet()) {
                /*xxx: wrapper的初始化参数,就是 servlet的初始化参数 */
                wrapper.addInitParameter(entry.getKey(), entry.getValue());
            }

            /*xxx: wrapper指代的类,就是servlet指代的类*/
            wrapper.setServletClass(servlet.getServletClass());

            /*xxx: 并将wrapper 作为上下文容器的子容器,进行保存 */
            context.addChild(wrapper);
        }
    }
}

# spring上下文的初始化方式

  1. spring上下文的初始化,本质上就是dispatcherServlet的初始化;
  2. dispatcherServlet初始化本身有自己的初始化时机,tomcat与spring上下文的结合也就体现在这里
public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
}

public abstract class HttpServlet extends javax.servlet.GenericServlet {
}

//package org.springframework.web.servlet;
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
    @Override
    /*xxx: 在服务器容器启动后,将会自动初始化 (init-param 设置为非负数,或者没设 在context完成后,会自动执行初始化)*/
    public final void init() throws ServletException {
        /*xxx: 将 servlet 中配置的参数 封装到 pvs 变量中,  requiredProperties 为 必需参数,如果没配置,将报异常*/
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);

        /*xxx: 模板方法,可以在子类调用,做一些初始化工作, bw代表 DispatcherServlet*/
        initBeanWrapper(bw);
        /*xxx: 将配置的 初始值,(如 contextConfigLocation) 设置到  DispatcherServlet*/
        bw.setPropertyValues(pvs, true);

        /*xxx: 模板方法,子类初始化的入口方法*/
        initServletBean();
    }

    protected void initServletBean() throws ServletException {
    }
}

/*xxx: 该方法重写了 除了 doHead外的所有方法*/
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
    /*xxx: springmvc 相关的bean 是否已经初始化完成 */
    private volatile boolean refreshEventReceived;

    private boolean publishContext = true;
    
    @Nullable
    private WebApplicationContext webApplicationContext;
    
    @Override
    protected final void initServletBean() throws ServletException {
        /*xxx: 初始化 WebApplicationContext*/
        this.webApplicationContext = initWebApplicationContext();
        /*xxx: 初始化 FrameworkServlet*/
        initFrameworkServlet();
    }

    protected WebApplicationContext initWebApplicationContext() {
        /*xxx: 从servletContext中 获取spring的 WebApplicationContext,名称为 WebApplicationContext的类全名 + .root */
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());

        WebApplicationContext wac = null;

        /*xxx: 如果 webApplicationContext还没有创建,则创建一个*/
        /*xxx: 正常情况下,就是走这个分支*/
        wac = createWebApplicationContext(rootContext);

        if (wac == null) {
            /*xxx: 当 webAppicationContext 已经存在 ServletContext中时,通过配置在 Servlet中的 contextAttribute参数获取*/
            /*xxx:  这种情况下,属于 不同的 context,有些没有初始化 spring的上下文,会使用其他context已经初始化好的 spring应用上下文 */
            wac = findWebApplicationContext();
        }
        /*xxx: 应用上下文初始化完成后,如果仍然没有更新 mvc的配置,则进行更新 */
        if (!this.refreshEventReceived) {
            synchronized (this.onRefreshMonitor) {
                /*xxx: 当ContextRefreshedEvent事件没有触发时,调用此方法,为模板方法*/
                /*xxx: 初始化springMvc的流程 */
                onRefresh(wac);
            }
        }

        /*xxx: 如果允许为公共的spring上下文 */
        /*xxx: 该值默认为 true */
        if (this.publishContext) {
            /*xxx: 将 ApplicationContext 保存到  ServletContext中*/
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }
    }

    protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
        return createWebApplicationContext((ApplicationContext) parent);
    }

    protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
        /*xxx: 获取创建类型, 默认为 org.springframework.web.context.support.XmlWebApplicationContext*/
        Class<?> contextClass = getContextClass();

        /*xxx: 检查创建类型*/
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            //阻断,并 报错
        }
        /*xxx: 具体创建相应的 上下文类 */
        ConfigurableWebApplicationContext wac =
                (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
        /*xxx: 将设置的 contextConfigLocation参数传给 wac  配置了才传递*/
        String configLocation = getContextConfigLocation();
        if (configLocation != null) {
            wac.setConfigLocation(configLocation);
        }
        /*xxx: 创建了上下文后,需要进行配置,以及 调用refresh方法*/
        configureAndRefreshWebApplicationContext(wac);
        return wac;
    }

    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
        /*xxx: 添加监听 ContextRefreshedEvent 的监听器*/
        wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

        /*xxx: 这里实际上,就进入了 spring上下文的逻辑 */
        /*xxx: 该方法会调用 applicationInitializer, 并进行应用*/
        applyInitializers(wac);
        wac.refresh();
    }

    /*xxx: spring层面的上下文初始化好后,将会通过事件机制,触发该方法的执行 */
    public void onApplicationEvent(ContextRefreshedEvent event) {
        this.refreshEventReceived = true;
        synchronized (this.onRefreshMonitor) {
            onRefresh(event.getApplicationContext());
        }
    }
}

public class DispatcherServlet extends FrameworkServlet {

    /*xxx: org.springframework.web.servlet.DispatcherServlet.properties里面定义的键值对*/
    /*xxx: 默认情况下,处理上传组件 multipartResolver是没有默认配置的*/
    private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
    
    /*xxx: 检测所有的 handlerMappings 还是 仅仅从上下文中获取 bean*/
    private boolean detectAllHandlerMappings = true;

    @Nullable
    private List<HandlerMapping> handlerMappings;
    
    @Override
    /*xxx: 该方法 在 spring层面的上下文执行完成后,进行调用 */
    protected void onRefresh(ApplicationContext context) {
        /*xxx: 初始化9个组件*/
        initStrategies(context);
    }

    protected void initStrategies(ApplicationContext context) {
        /*xxx: 1.MultipartResolver组件*/
        initMultipartResolver(context);
        /*xxx: 2.localeResolver组件*/
        initLocaleResolver(context);
        /*xxx: 3.themeResolver组件*/
        initThemeResolver(context);
        /*xxx: 4.handlerMapping组件*/
        initHandlerMappings(context);
        /*xxx: 5.handlerAdapter组件*/
        initHandlerAdapters(context);
        /*xxx: 6.handlerExceptionResolver组件*/
        initHandlerExceptionResolvers(context);
        /*xxx: 7.requestToViewNameTranslator组件*/
        initRequestToViewNameTranslator(context);
        /*xxx: 8.viewResolver组件*/
        initViewResolvers(context);
        /*xxx: 9.flashMapManager组件*/
        initFlashMapManager(context);
    }

    private void initHandlerMappings(ApplicationContext context) {
        /*xxx: 获取所有的 handlerMapping */
        if (this.detectAllHandlerMappings) {
            /*xxx: 从上下文中,以类型的方式,获取 bean, 父级上下文中的同类型bean,也会获取到  */
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList<>(matchingBeans.values());
                /*xxx: handlerMapping 会根据 order 进行排序 */
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        }else{
            HandlerMapping hm = context.getBean("handlerMapping", HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }

        /*xxx: 如果没有配置 handlerMapping,则会使用默认的  handlerMapping */
        /*xxx: 默认情况下,包括: BeanNameUrlHandlerMapping, RequestMappingHandlerMapping, RouterFunctionMapping */
        if (this.handlerMappings == null) {
            /*xxx: 默认配置的 handlerMapping ,不会进行排序,按照先后顺序  依次排开 */
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        }
    }

    private void initHandlerAdapters(ApplicationContext context) {
        /*xxx: 同 handlerMapping, 
           默认的 handlerMapping 包括:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,RequestMappingHandlerAdapter,HandlerFunctionAdapter* */
    }
}

# 最佳实践--springBoot的结合

# 内置tomcat如何装载Servlet,Filter和Listener

  • 动态注册体系设计
//package org.springframework.boot.web.servlet;

public interface ServletContextInitializer {
    /*xxx: 启动钩子 */
    void onStartup(ServletContext servletContext) throws ServletException;
}

public abstract class RegistrationBean implements ServletContextInitializer, Ordered {

    public final void onStartup(ServletContext servletContext) throws ServletException {
        String description = this.getDescription();
        this.register(description, servletContext);
    }

    protected abstract void register(String description, ServletContext servletContext);
}

public abstract class DynamicRegistrationBean<D extends Dynamic> extends RegistrationBean {
    protected final void register(String description, ServletContext servletContext) {
        D registration = this.addRegistration(description, servletContext);
    }

    protected abstract D addRegistration(String description, ServletContext servletContext);
}

public class ServletRegistrationBean<T extends Servlet> extends DynamicRegistrationBean<Dynamic> {
    
    protected Dynamic addRegistration(String description, ServletContext servletContext) {
        String name = this.getServletName();
        return servletContext.addServlet(name, this.servlet);
    }
}
  • 动态注册流程设计
/*xxx: servlet规范的  容器初始化器 */
public interface ServletContainerInitializer {
    void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}

final class TomcatStarter implements ServletContainerInitializer {
    private final ServletContextInitializer[] initializers;

    TomcatStarter(ServletContextInitializer[] initializers) {
        this.initializers = initializers;
    }
    @Override
    public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
        for (ServletContextInitializer initializer : this.initializers) {
            initializer.onStartup(servletContext);
        }
    }
}

public interface ServletWebServerFactory {
    WebServer getWebServer(ServletContextInitializer... initializers);
}

public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory implements ConfigurableTomcatWebServerFactory {

    @Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();
        prepareContext(tomcat.getHost(), initializers);
    }

    protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
        /*xxx: 是 StandardContext的变体*/
        TomcatEmbeddedContext context = new TomcatEmbeddedContext();
        /*xxx: 为 context 添加 Initializers*/
        configureContext(context, initializersToUse);
    }

    protected void configureContext(Context context, ServletContextInitializer[] initializers) {
        TomcatStarter starter = new TomcatStarter(initializers);
        /*xxx:为context 添加servlet容器初始化器*/
        context.addServletContainerInitializer(starter, NO_CLASSES);
    }
}

public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {
    @Override
    /*xxx: context的启动逻辑,比较复杂*/
    protected synchronized void startInternal() throws LifecycleException {
        for (Entry<ServletContainerInitializer, Set<Class<?>>> entry :
                initializers.entrySet()) {
                /*xxx: 20.启动添加到当前上下文的  ServletContainerInitializer,该类的实例,由 ContextConfig查找并添加*/
                /*xxx: 该类主要用于 以可编程的方式添加Web应用的配置,如Servlet,Filter等 */
                entry.getKey().onStartup(entry.getValue(),
                        getServletContext());
        }
    }
}

public class ServletWebServerApplicationContext extends GenericWebApplicationContext
        implements ConfigurableWebServerApplicationContext {
    /*xxx: 获取contextInitializer集合*/
    private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
        return servletContext -> selfInitialize(servletContext);
    }

    private void selfInitialize(ServletContext servletContext) throws ServletException {
        prepareWebApplicationContext(servletContext);
        registerApplicationScope(servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
        for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
            beans.onStartup(servletContext);
        }
    }
    
    protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
        return new ServletContextInitializerBeans(getBeanFactory());
    }
}

public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer> {
    /*xxx: 该bean 在初始化的时候,还会调用适配方法,添加 动态注册的filter以及 servlet,listener等*/
    public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
                                          Class<? extends ServletContextInitializer>... initializerTypes) {
        addServletContextInitializerBeans(beanFactory);
        addAdaptableBeans(beanFactory);
    }

    private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
        for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
            for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,
                    initializerType)) {
                addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
            }
        }
    }

    /*xxx: 通过bean注册相应的组件 */
    private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
                                                  ListableBeanFactory beanFactory) {
        if (initializer instanceof ServletRegistrationBean) {
            Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
            addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof FilterRegistrationBean) {
            Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
            addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
        }
        /*xxx: 代理filter,单独作为了一个 Filter类型进行处理 */
        else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
            String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
            addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof ServletListenerRegistrationBean) {
            EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
            addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
        }
        else {
            addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory,
                    initializer);
        }
    }

    private void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer,
                                                  ListableBeanFactory beanFactory, Object source) {
        this.initializers.add(type, initializer);
    }

    protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
        addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
        addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
    }

    protected <T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,
                                             RegistrationBeanAdapter<T> adapter) {
        addAsRegistrationBean(beanFactory, type, type, adapter);
    }

    private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,
                                                        Class<B> beanType, RegistrationBeanAdapter<T> adapter) {
        List<Entry<String, B>> entries = getOrderedBeansOfType(beanFactory, beanType, this.seen);
        /*xxx: 遍历相应的组件集合 */
        for (Entry<String, B> entry : entries) {
            String beanName = entry.getKey();
            B bean = entry.getValue();
            /*xxx: 如果该组件 尚未被注册,则将之包装成 registration,并进行注册*/
            if (this.seen.add(bean)) {
                RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
                int order = getOrder(bean);
                registration.setOrder(order);
                this.initializers.add(type, registration);
            }
        }
    }
}

# spring上下文的初始化方式及启动方式

public class ServletWebServerApplicationContext extends GenericWebApplicationContext
		implements ConfigurableWebServerApplicationContext {
    @Override
    /*xxx: springBoot的web应用,就是在该方法中,启动了内置的tomcat容器 */
    protected void onRefresh() {
        super.onRefresh();
        try {
            createWebServer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start web server", ex);
        }
    }

    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = getServletContext();
        /*xxx: webServer与 servletContext都不为空, fatJar环境走的就是该分支 */
        if (webServer == null && servletContext == null) {
            StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
            ServletWebServerFactory factory = getWebServerFactory();
            createWebServer.tag("factory", factory.getClass().toString());
            /*xxx: 第一步比较关键的是,通过工厂获取 webServer时,进行初始化工作*/
            /*xxx: 在初始化时,同时指定了 ServletContextInitializer集合*/
            this.webServer = factory.getWebServer(getSelfInitializer());
            createWebServer.end();
            getBeanFactory().registerSingleton("webServerGracefulShutdown",
                    new WebServerGracefulShutdownLifecycle(this.webServer));
            /*xxx: 第二部关键点是,为上下文容器新增一个  webServer的起停器,它是一个 smartLifecycle,会自动启动*/
            getBeanFactory().registerSingleton("webServerStartStop",
                    new WebServerStartStopLifecycle(this, this.webServer));
        }
        /*xxx: 如果webServer为空,但是 servlet不为空,war部署的时候,走的该分支*/
        else if (servletContext != null) {
            try {
                /*xxx: war时的机制,与fatjar保持一致*/
                getSelfInitializer().onStartup(servletContext);
            }
            catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context", ex);
            }
        }
    }

    /*xxx: 获取contextInitializer集合*/
    private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
        return servletContext -> selfInitialize(servletContext);
    }

    private void selfInitialize(ServletContext servletContext) throws ServletException {
        prepareWebApplicationContext(servletContext);
        registerApplicationScope(servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
        for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
            beans.onStartup(servletContext);
        }
    }

    protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
        return new ServletContextInitializerBeans(getBeanFactory());
    }
}

public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer> {
    /*xxx: 该bean 在初始化的时候,还会调用适配方法,添加 动态注册的filter以及 servlet,listener等*/
    public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
                                          Class<? extends ServletContextInitializer>... initializerTypes) {
        addServletContextInitializerBeans(beanFactory);
        addAdaptableBeans(beanFactory);
    }

    private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
        for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
            for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,
                    initializerType)) {
                addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
            }
        }
    }

    /*xxx: 通过bean注册相应的组件 */
    private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
                                                  ListableBeanFactory beanFactory) {
        if (initializer instanceof ServletRegistrationBean) {
            Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
            addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof FilterRegistrationBean) {
            Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
            addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
        }
        /*xxx: 代理filter,单独作为了一个 Filter类型进行处理 */
        else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
            String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
            addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof ServletListenerRegistrationBean) {
            EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
            addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
        }
        else {
            addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory,
                    initializer);
        }
    }

    private void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer,
                                                  ListableBeanFactory beanFactory, Object source) {
        this.initializers.add(type, initializer);
        if (source != null) {
            this.seen.add(source);
        }
    }

    protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
        MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
        addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
        addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
        for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {
            addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,
                    new ServletListenerRegistrationBeanAdapter());
        }
    }

    private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,
                                                        Class<B> beanType, RegistrationBeanAdapter<T> adapter) {
        List<Entry<String, B>> entries = getOrderedBeansOfType(beanFactory, beanType, this.seen);
        /*xxx: 遍历相应的组件集合 */
        for (Entry<String, B> entry : entries) {
            String beanName = entry.getKey();
            B bean = entry.getValue();
            /*xxx: 如果该组件 尚未被注册,则将之包装成 registration,并进行注册*/
            if (this.seen.add(bean)) {
                RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
                int order = getOrder(bean);
                registration.setOrder(order);
                this.initializers.add(type, registration);
            }
        }
    }
}
  • springBoot上下文如何与embbed-tomcat联动
public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext var1) throws BeansException;
}

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
    private WebApplicationContext webApplicationContext;

    private boolean webApplicationContextInjected;

    public void setApplicationContext(ApplicationContext applicationContext) {
        if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
            this.webApplicationContext = (WebApplicationContext)applicationContext;
            this.webApplicationContextInjected = true;
        }
    }
}
  • dispatcher 在 tomcat环境中,充当的是普通的java类实例,spring的上下文由servlet流程初始化;
  • dispatcher 在 tomcat-embbed环境中,充当的是spring的bean,spring的上下文,由spring流程自动注入;

# 最佳实践--性能探究

# 工作线程数

  • 代码体现
public abstract class AbstractEndpoint<S,U> {

    /*xxx: 工作线程池*/
    private Executor executor = null;

    /*xxx: 最大工作线程数,默认200*/
    private int maxThreads = 200;

    /*xxx: 是否使用内部线程池*/
    protected volatile boolean internalExecutor = true;
    
    /*xxx: 创建线程池,*/
    public void createExecutor() {
        internalExecutor = true;
        TaskQueue taskqueue = new TaskQueue();
        TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
        /*xxx: 创建工作线程池时,线程池最低保持了10个线程,最大可以达到参数设置的线程数,默认情况下是200 */
        executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
        taskqueue.setParent( (ThreadPoolExecutor) executor);
    }

    public int getMaxThreads() {
        if (internalExecutor) {
            return maxThreads;
        } else {
            return -1;
        }
    }
}
  • 配置项

配置 tomcat/conf/server.xml

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="500" />
  • 物理意义 每一次HTTP请求到达Web服务,tomcat都会创建一个线程来处理该请求,那么最大线程数决定了Web服务容器可以同时处理多少个请求。maxThreads默认200,肯定建议增加。但是,增加线程是有成本的,更多的线程,不仅仅会带来更多的线程上下文切换成本,而且意味着带来更多的内存消耗。JVM中默认情况下在创建新线程时会分配大小为1M的线程栈,所以,更多的线程异味着需要更多的内存。线程数的经验值为:1核2g内存,线程数经验值200;4核8g内存,线程数经验值800。

# 连接队列数

  • 代码体现
public abstract class AbstractEndpoint<S,U> {
    /*xxx: 允许服务端接收的线程,默认 100*/
    private int acceptCount = 100;

    public int getAcceptCount() { return acceptCount; }

    /*xxx:初始化时,会进行 创建服务端的 nio socketChannel*/
    protected void initServerSocket() throws Exception {
        InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
        /*xxx: accept队列的长度,该值作用于操作系统
            当accept队列中连接的个数达到acceptCount时,队列满,进来的请求一律被拒绝。默认值是100*/
        serverSock.socket().bind(addr,getAcceptCount());
    }
}
  • 配置项

配置 tomcat/conf/server.xml

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" acceptCount="500" />
  • 物理意义

官方文档的说明为:当所有的请求处理线程都在使用时,所能接收的连接请求的队列的最大长度。当队列已满时,任何的连接请求都将被拒绝。accept-count的默认值为100。 详细的来说:当调用HTTP请求数达到tomcat的最大线程数时,还有新的HTTP请求到来,这时tomcat会将该请求放在等待队列中,这个acceptCount就是指能够接受的最大等待数,默认100。如果等待队列也被放满了,这个时候再来新的请求就会被tomcat拒绝(connection refused)

# 最大连接数

  • 代码体现
public abstract class AbstractEndpoint<S,U> {

    /*xxx: Tomcat在任意时刻接收和处理的最大连接数, 默认为 8192*/
    private int maxConnections = 8*1024;

    /*xxx: 暂存所有与当前的socket相连的所有连接,通过 maxConnections 可以进行控制 */
    protected Map<U, SocketWrapperBase<S>> connections = new ConcurrentHashMap<>();

    public int getMaxConnections() { return this.maxConnections; }
}

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel> {

    @Override
    protected boolean setSocketOptions(SocketChannel socket) {
        NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);
        channel.reset(socket, newWrapper);
        /*xxx: 将新建的连接进行保存,该变量保存了 tomcat任意时刻的活跃连接数 */
        connections.put(socket, newWrapper);
        return true;
    }
}

public class Acceptor<U> implements Runnable {
    @Override
    public void run() {
        while (!stopCalled) {
            /*xxx: 增加endPoint的连接数,如果达到了最大连接数,则阻塞等待*/
            /*xxx: 当 endpoint的连接数,小于 最大连接数时,才从队列中,获取socket连接*/
            endpoint.countUpOrAwaitConnection();
        }
    }
}
  • 配置项

配置 tomcat/conf/server.xml

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" maxConnections="1000" />
  • 物理意义

这个参数是指在同一时间,tomcat能够接受的最大连接数。对于Java的阻塞式BIO,默认值是maxthreads的值;如果在BIO模式使用定制的Executor执行器,默认值将是执行器中maxthreads的值。对于Java 新的NIO模式,maxConnections 默认值是10000。 对于windows上APR/native IO模式,maxConnections默认值为8192,这是出于性能原因,如果配置的值不是1024的倍数,maxConnections 的实际值将减少到1024的最大倍数。 如果设置为-1,则禁用maxconnections功能,表示不限制tomcat容器的连接数。 maxConnections和accept-count的关系为:当连接数达到最大值maxConnections后,系统会继续接收连接,但不会超过acceptCount的值。

# 外置tomcat的主要配置

# server.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>

<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />

  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost">

      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>

# web.xml的配置结构及优先级

  • 配置结构
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1">


    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>


  
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>


    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>
  • 优先级 context的web.xml优先级> 全局的web.xml

# 外置tomcat与内置tomcat的本质区别

# 外置tomcat创建容器的方式

public class MBeanFactory {
    public String createStandardContext(String parent, String path, String docBase, boolean xmlValidation, boolean xmlNamespaceAware) throws Exception {
        StandardContext context = new StandardContext();
        ContextConfig contextConfig = new ContextConfig();
        context.addLifecycleListener(contextConfig);
        Service service = this.getService(pname);
        Engine engine = service.getContainer();
        Host host = (Host)engine.findChild(pname.getKeyProperty("host"));
        host.addChild(context);
    }

    public String createStandardHost(String parent, String name, String appBase, boolean autoDeploy, boolean deployOnStartup, boolean deployXML, boolean unpackWARs) throws Exception {
        StandardHost host = new StandardHost();
        host.setName(name);
        host.setAppBase(appBase);
        host.setAutoDeploy(autoDeploy);
        host.setDeployOnStartup(deployOnStartup);
        host.setDeployXML(deployXML);
        host.setUnpackWARs(unpackWARs);
        HostConfig hostConfig = new HostConfig();
        host.addLifecycleListener(hostConfig);
        ObjectName pname = new ObjectName(parent);
        Service service = this.getService(pname);
        Engine engine = service.getContainer();
        engine.addChild(host);
        return host.getObjectName().toString();
    }

    public String createStandardServiceEngine(String domain, String defaultHost, String baseDir) throws Exception {
        if (!(this.container instanceof Server)) {
            throw new Exception(sm.getString("mBeanFactory.notServer"));
        } else {
            StandardEngine engine = new StandardEngine();
            engine.setDomain(domain);
            engine.setName(domain);
            engine.setDefaultHost(defaultHost);
            Service service = new StandardService();
            service.setContainer(engine);
            service.setName(domain);
            ((Server)this.container).addService(service);
            return engine.getObjectName().toString();
        }
    }
}

# 内置tomcat创建容器的流程

public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory implements ConfigurableTomcatWebServerFactory {
    protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
        /*xxx: 是 StandardContext的变体*/
        TomcatEmbeddedContext context = new TomcatEmbeddedContext();
        /*xxx: 将 context添加为 host的子组件*/
        host.addChild(context);
    }

    @Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();
        /*xxx: host组件,用的默认的 standardHost组件*/
        tomcat.getHost().setAutoDeploy(false);
        prepareContext(tomcat.getHost(), initializers);
    }
}

```java
/*xxx: 提供一种轻量级的扩展方式启动 tomcat,使得应用可以内嵌运行*/
public class Tomcat {
    public Server getServer() {
        server = new StandardServer();
        Service service = new StandardService();
        service.setName("Tomcat");
        server.addService(service);
    }

    public Engine getEngine() {
        Service service = getServer().findServices()[0];
        Engine engine = new StandardEngine();
        service.setContainer(engine);
    }

    public Host getHost() {
        Engine engine = getEngine();
        Host host = new StandardHost();
        getEngine().addChild(host);
    }
}

# 过滤器改造

# 过滤器改造优先级

  • 对于springBoot环境,@Order越小,优先级越高
  • 对于非springBoot环境,采用web.xml方式配置过滤器时,按照先后顺序构建过滤链

# 响应头设置的要点

  • 设置响应头,对于先后时序要求的,尽量在 当前链过滤前加上,避免因调用了response.commit导致添加失败
  • 对于有先后时序要求的(比如改写cookie),需要确保response的未commit. 常见的flushBuffer,缓冲区满均会导致response切换为commit状态;
  • 对于某些自定义的请求头,要被浏览器保留并识别,需要设置请求头:response.setHeader("Access-Control-Expose-Headers", "the header name")

# servlet外观模式专题

# 外观模式的架构

  • coyoter Request 和 Response
public class Http11Processor extends AbstractProcessor {
	public Http11Processor(AbstractHttp11Protocol<?> protocol, Adapter adapter) {
        super(adapter);
     	//省略其他抽象,协议将原生的socket流,转为 coyote 的Request 和Response
        
    }
}

public abstract class AbstractProcessor extends AbstractProcessorLight implements ActionHook {
    protected final Request request;
    protected final Response response;
    
 	public AbstractProcessor(Adapter adapter) {
        this(adapter, new Request(), new Response());
    }   
}

/*xxx: 适配器,用于找到请求对应的 组件*/
public class CoyoteAdapter implements Adapter {
    /*xxx: 可以看成tomcat的核心流程的处理起点 多线程环境*/
    public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
            throws Exception {
        //... 省略其他抽象
     	request = connector.createRequest();
        request.setCoyoteRequest(req);
        response = connector.createResponse();   
        response.setCoyoteResponse(res);
        //... 省略其他抽象
        
    }
 	   
}
  • connector Request 和 Response (已经是属于servlet规范的Request和Response)
/*xxx: 连接器,对应于协议,用于 处理协议, 一个具有生命周期的组件*/
public class Connector extends LifecycleMBeanBase  {
    
 	public Request createRequest() {
        return new Request(this);
    }
    
    public Response createResponse() {
        int size = protocolHandler.getDesiredBufferSize();
        if (size > 0) {
            return new Response(size);
        } else {
            return new Response();
        }
    }
}

public class Request implements HttpServletRequest {
	//xxx: 原生连接器, 本质上是一个连接处理器 (单线程,将进来的请求分发给 其他线程处理,之后的处理过程将与该线程无关)
	protected final Connector connector;
	
	//xxx: coyote Request,servlet规范的很多方法的最终实现,均由其完成
	//xxx: 不为空
	/*xxx: 个别规范,也会在 当前类 进行处理*/
	protected org.apache.coyote.Request coyoteRequest;
	
	//xxx: 外观模式的代理对象 的 出口
	protected RequestFacade facade = null;
	
	/*xxx: 外观模式 代理*/
    private HttpServletRequest applicationRequest = null;
    
    /*xxx: 设置 外观包装器 的代理对象*/
    public void setRequest(HttpServletRequest applicationRequest) {
        // Check the wrapper wraps this request
        ServletRequest r = applicationRequest;
        while (r instanceof HttpServletRequestWrapper) {
            r = ((HttpServletRequestWrapper) r).getRequest();
        }
        /*xxx: 包装器的尽头,必需是 RequestFacade*/
        if (r != facade) {
            throw new IllegalArgumentException(sm.getString("request.illegalWrap"));
        }
        this.applicationRequest = applicationRequest;
    }
	
	/*xxx: 获取外观模式代理对象*/
    public HttpServletRequest getRequest() {
        if (facade == null) {
            facade = new RequestFacade(this);
        }
        if (applicationRequest == null) {
            applicationRequest = facade;
        }
        return applicationRequest;
    }
}
public class Response implements HttpServletResponse {
    
    /*xxx: 缓存流处理器*/
    protected final OutputBuffer outputBuffer;
    
    /*xxx: 外观模式代理的最终对象*/
    protected ResponseFacade facade = null;
    
    /*xxx: 实际响应的处理*/
    /*xxx: 个别规范,也会在 当前类 进行处理*/
    protected org.apache.coyote.Response coyoteResponse;
    
    /*xxx: 外观模式的代理对象*/
    private HttpServletResponse applicationResponse = null;

	public Response() {
        //xxx: 默认流缓存处理8M数据
        this(OutputBuffer.DEFAULT_BUFFER_SIZE);
    }
    
    /*xxx: 获取外观代理对象 */
    public HttpServletResponse getResponse() {
        if (facade == null) {
            facade = new ResponseFacade(this);
        }
        if (applicationResponse == null) {
            applicationResponse = facade;
        }
        return applicationResponse;
    }
    
    /*xxx: 设置外观代理对象*/
    public void setResponse(HttpServletResponse applicationResponse) {
        ServletResponse r = applicationResponse;
        while (r instanceof HttpServletResponseWrapper) {
            r = ((HttpServletResponseWrapper) r).getResponse();
        }
        /*xxx: 外观代理模式的尽头,必需是 facade */
        if (r != facade) {
            throw new IllegalArgumentException(sm.getString("response.illegalWrap"));
        }
        this.applicationResponse = applicationResponse;
    }
}
  • 外观对象,是在filter,servelt流通的基本对象
public class RequestFacade implements HttpServletRequest {
 	public RequestFacade(Request request) {
        this.request = request;
    }   
}

public class ResponseFacade implements HttpServletResponse {
 	public ResponseFacade(Response response) {
         this.response = response;
    }   
}

# 外观模式的流程

final class StandardWrapperValve
    extends ValveBase {
 	
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        //..... 省略其他抽象
        
     	/*xxx: 从这里,开始进入 Servlet规范,进行处理*/
        /*xxx: 过滤链的构建,由过滤链构造器完成 */
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
        
        /*xxx: 通过原生过滤链的过滤操作,完成 servlet的功能*/
                            /*xxx: request.getRequest(),respon.getResponse(),获取的是外观对象。  本质上来说,获取的是一个代理对象*/
         filterChain.doFilter(request.getRequest(),
                                    response.getResponse());
        
        //xxx: 省略其他抽象...
        
    }
}
  • 在过滤链的传递过程中,可以通过ServletRequestWrapper 为 外观对象进行 穿衣服 的过程,当过滤器出栈的时候,又会进入 脱衣服 的过程.

  • 换言之,在不进行过滤器包装的情况下,流通的实际servlet对象为 Facade.

  • 如果要进行保证,包装器最里面的核心对象,必需为 Facade.

# 外观模式的包装架构

public class ServletRequestWrapper implements ServletRequest {
    private ServletRequest request;
    
    public ServletRequestWrapper(ServletRequest request) {
        if (request == null) {
            throw new IllegalArgumentException(lStrings.getString("wrapper.nullRequest"));
        }
        this.request = request;
    }
}

public class HttpServletRequestWrapper extends ServletRequestWrapper implements
        HttpServletRequest {
    
 	public HttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }   
    
    /*xxx: 获取包装对象*/
    private HttpServletRequest _getHttpServletRequest() {
        return (HttpServletRequest) super.getRequest();
    }
}

# 外观模式的关键点

  • 外观模式的代理操作,操作一定是单向的,有明确的代理出口,不能存在环
  • 外观模式,有点类似于穿衣服,于脱衣服,有两个关键因素都会影响最终的效果
    • 在何时包装
    • 在何时调用