tomcat7 源码分析

tomcat7源码分析

本篇分为六个部分:

tomcat基本框架

tomcat启动流程简介

tomcat启动流程源码分析

tomcat处理一个请求过程分析

.jsp生成.java和.class流程分析

apache beachmark性能测试

一、tomcat基本框架

由三部分组成:

组件架构:组件搭起房梁

基于JMX:JMX管理组件等对象

事件侦听:通过事件变更状态

  1. 组件架构结构

1.1 结构图:

《tomcat7 源码分析》



组件简述: Catalina:与开始/关闭shell脚本交互的主类,因此如果要研究启动和关闭的过程,就从这个类开始看起。 Server:是整个Tomcat组件的容器,包含一个或多个Service。 Service:Service是包含Connector和Container的集合,Service用适当的Connector接收用户的请求,再发给相应的Container来处理。 Connector:实现某一协议的连接器,如默认的有实现HTTP、HTTPS、AJP协议的。 Container:可以理解为处理某类型请求的容器,处理的方式一般为把处理请求的处理器包装为Valve对象,并按一定顺序放入类型为Pipeline的管道里。Container有多种子类型:Engine、Host、Context和Wrapper,这几种子类型Container依次包含,处理不同粒度的请求。另外Container里包含一些基础服务,如Loader、Manager和Realm。 Engine:Engine包含Host和Context,接到请求后仍给相应的Host在相应的Context里处理。 Host:就是我们所理解的虚拟主机。 Context:就是我们所部属的具体Web应用的上下文,说白了就是我们的应用,每个请求都在是相应的上下文里处理的。 Wrapper:Wrapper是针对每个Servlet的Container,每个Servlet都有相应的Wrapper来管理。 可以看出Server、Service、Connector、Container、Engine、Host、Context和Wrapper这些核心组件的作用范围是逐层递减,并逐层包含。 下面就是些被Container所用的基础组件: Loader:是被Container用来载入各种所需的Class。 Manager:是被Container用来管理Session池。 Realm:是用来处理安全里授权与认证。 

1.2 组件关系

service直接包含connector(可多个)containtor(一个),这好比一个家庭,男主外,女主内。service是房子,connector是男子,主要工作是对外;Container是女子,处理家里内部事务。connector和service一起组件一个家庭,住在service这个房子里
  1. JMX管理组件
Tomcat会为每个组件进行注册过程,通过Registry管理起来,而Registry是基于JMX来实现的,因此在看组件的init和start过程实际上就是初始化MBean和触发MBean的start方法,会大量看到形如:


Registry.getRegistry(null, null).invoke(mbeans, "init", false);


Registry.getRegistry(null, null).invoke(mbeans, "start", false);


这样的代码,这实际上就是通过JMX管理各种组件的行为和生命期。
  1. 事件侦听
各个组件在其生命期中会有各种各样行为,而这些行为都有触发相应的事件,Tomcat就是通过侦听这些时间达到对这些行为进行扩展的目的。在看组件的init和start过程中会看到大量如: lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);这样的代码,这就是对某一类型事件的触发,如果你想在其中加入自己的行为,就只用注册相应类型的事件即可。

二、tomcat启动流程简介

启动时主要流程如下:
1. 初始化类加载器:主要初始化Tomcat加载自身类库的StandardClassLoader(commonClassLoader等)。

  1. 解析conf/serverl.xml配置文件:使用Digester解析Tomcat的server.xml(SAXReader),初始化各个组件(包含各个web应用,解析对应的web.xml进行初始化)。

  2. 初始化容器:初始化Service的各级容器Container,包括我们Web应用(我们熟悉的Listener,Filter,Servlet等初始化等在这里完成)。

  3. 初始化Connector:初始化Service的的Connector

  4. 初始化后,等待请求的到来

  5. 时序图
    《tomcat7 源码分析》

《tomcat7 源码分析》

从上图可以看出,Tomcat启动分为init和start两个过程,核心组件都实现了Lifecycle接口,都需实现start方法,因此在start过程中就是从Server开始逐层调用子组件的start过程。
下面我们就根据时序图结合源码进行分析

三、tomcat7启动流程源码分析

从catalina.bat找到启动开始的地方:Bootstrap类,它中有个main方法

set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=

Bootstrap.main开始

public static void main(String args[]) {
        System.out.println("-- my test starting --");


        if (daemon == null) { 
            // Don't set daemon until init() has completed
            Bootstrap bootstrap = new Bootstrap();
            try {
                //set一些系统属性、初始化classLoader和Catalina.setParentClassLoader()
                bootstrap.init()
            } catch (Throwable t) {}
            daemon = bootstrap;
        } 

        String command = "start";


        if (command.equals("start")) {
            daemon.setAwait(true);

            //加载配置资源,通过反射调用catalina.load方法,利用catalina.load方法创建digester实例,从而解析conf/server.xml文件
            daemon.load(args);

            //运行各个组件,容器开始启动
            daemon.start();
        }
}

从代码可以看出,main方法主要做三件事:

init、load、start

init: 初始化类加载器
load:加载conf/server.xml,根据规则解析元素为对应对象,并set属性,元素间关联关系,且变更各个对象生命周期状态
start:启动各个组件

调用Bootstrap.init()

主要做了两件事:
1. 设置catalinahome和catalinbase(即java的vm options的值:”E:\tomcat_test\apache-tomcat-7.0.73-src\lunch”
2. 实例化**ClassLoaders

public void init() throws Exception {
        // Set Catalina path
        setCatalinaHome();
        setCatalinaBase();


        //实例化**ClassLoaders,创建URLClassLoader
        initClassLoaders();


        Thread.currentThread().setContextClassLoader(catalinaLoader);


        SecurityClassLoad.securityClassLoad(catalinaLoader);


        // Load our startup class and call its process() method
        Class<?> startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.newInstance();


        catalinaDaemon = startupInstance;


    }

调用Bootstrap.load(args)

通过反射实例化org.apache.catalina.startup.Catalina,并调用catalina.load(),在load方法中做了下面的事:
1. Digester类按照预定的规则解析server.xml,元素转化为对象,包括构造对象,set属性到对象字段,同时维护相互关联关系
2. 调用Server.init()方法,这其中会一连串的发布事件病调用各个service.init()方法,完成各个组件的初始化,各个组件包括:StandardServer、StandardService、StandardEngine、StandardHost、StandardContext、StandardWrapper。从StandardServer.init()到StandardWrapper.init()演示了这一过程

Catalina.load()
public void load() {
    // Create and execute our Digester
    //预定义了解析规则
    Digester digester = createStartDigester();


    try {
        // 获取conf/server.xml文件
        file = configFile();
        inputStream = new FileInputStream(file);
        inputSource = new InputSource(file.toURI().toURL().toString());

        inputSource.setByteStream(inputStream);
        digester.push(this);
        // 解析conf/server.xml文件(SAX),并根据规则初始化各个组件实例和关联关系:如server元素实例化standardServer实例对象,把属性内容set到对应实例中
        digester.parse(inputSource);
    } catch (SAXParseException spe) {

    } 
    // server关联catalina,在解析server.xml过程中,会发现父子元素对应实例的相互关联性(双向性)
    getServer().setCatalina(this);


    // Start the new server
    try {
        // 调用各个组件的init方法,初始化各个组件 
        getServer().init();
    } catch (LifecycleException e) {

    }
}



StandardServer.init()

上述各个组件有个共同的父类:LifecycleBase,用于管理组件的生命周期和状态变化。在走Server.init()前,先走父类LifecycleBase.init()方法,事件驱动当前组件状态的变化

LifecycleBase.init()

变更状态(通过事件变更),进入子类initInternal()方法

public final synchronized void init() throws LifecycleException {
    try {
        //变更生命周期状态(通过事件变更)
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        // 进入子类的initInternal()方法
        initInternal();
        setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t) {}
}

从StandardServer到StandardWrapper,都会调用initInternal(),并伴随调用共有父类LifecycleBase.init()

StandardServer.init()方法

核心代码功能:
1. 注册mbean
2. 调用service.init()方法,同样,先走LifecycleBase.init()

protected void initInternal() throws LifecycleException {
    // Register the MBeanFactory
    MBeanFactory factory = new MBeanFactory();
    factory.setContainer(this);
    onameMBeanFactory = register(factory, "type=MBeanFactory");

    // Register the naming resources
    globalNamingResources.init();

    // Initialize our defined Services
    for (int i = 0; i < services.length; i++) {
        services[i].init();
    }
}

service.initInternal()方法

该方法初始化StandardEngine组件,Connector对象

protected void initInternal() throws LifecycleException {


    super.initInternal();

    if (container != null) {
        // container:StandardEngine
        container.init();
    }


    // Initialize any Executors
    for (Executor executor : findExecutors()) {
        if (executor instanceof LifecycleMBeanBase) {
            ((LifecycleMBeanBase) executor).setDomain(getDomain());
        }
         // TODO executor是谁,默认没有
        executor.init();
    }


    // 实例化组件集合,默认两个,对应server.xml的connector元素
    synchronized (connectorsLock) {
        for (Connector connector : connectors) {
            try {
                connector.init();
            } catch (Exception e) {}
        }
    }
}

container.init()[StandardEngine.init()]

从此处开始,会初始化一系列container,直到wrapper

protected void initInternal() throws LifecycleException {
    // Ensure that a Realm is present before any attempt is made to start
    // one. This will create the default NullRealm if necessary.
    getRealm();
    // 创建a startStopExecutor
    super.initInternal();
}

Connector.init()

连接器初始化,创建CoyoteAdapter对象,具体协议类型初始化

protected void initInternal() throws LifecycleException {


    super.initInternal();


    // Initialize adapter
    //该协议适配器会完成请求的真正处理 
    adapter = new CoyoteAdapter(this);

      //对于不同的协议类型,会有不同的ProtocolHandler实现类,如:Http11Protocol用来处理HTTP请求 
    protocolHandler.setAdapter(adapter);


    try {
        // 初始化具体协议类型,如Http11Protocol协议
        protocolHandler.init();
    } catch (Exception e) {

    }


    // Initialize mapper listener
    mapperListener.init();
}

abstractProtocol.init()

代码功能:
1. 注册组件JIoEndPoint
2. endpoint.init(),设置work threads的数量,默认为200,并创建serverSocket对象

public void init() throws Exception {

    if (this.domain != null) {
        try {
            tpOname = new ObjectName(domain + ":" + "type=ThreadPool,name=" + getName());
            Registry.getRegistry(null, null).registerComponent(endpoint, tpOname, null);
        } catch (Exception e) {}

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


    try {
        //调用JIoEndpoint的初始化方法 
        endpoint.init();
    } catch (Exception ex) {}
}

endpoint.init()

public final void init() throws Exception {

    if (bindOnInit) {
        // 设置线程数、网络连接数
        bind();
        bindState = BindState.BOUND_ON_INIT;
    }
}

endpoint.bind()方法

public void bind() throws Exception 
    // Initialize maxConnections
    if (getMaxConnections() == 0) {
        // User hasn't set a value - use the default

        // 此值为server.xml的connector元素的属性MaxThreads值,默认200
        setMaxConnections(getMaxThreadsInternal());
    }


    if (serverSocketFactory == null) {
        if (isSSLEnabled()) {
            serverSocketFactory = handler.getSslImplementation().getServerSocketFactory(this);
        } else {
            serverSocketFactory = new DefaultServerSocketFactory(this);
        }
    }


    // 创建serverSocket对象
    try {
        if (getAddress() == null) {
            serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog());
        } 
    } catch (BindException orig) { }

}

调用Bootstrap.start()

通过反射调用Catalina.start()

public void start() throws Exception {
    if( catalinaDaemon==null ) init();


    Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
    method.invoke(catalinaDaemon, (Object [])null);
}

Catalina.start()

使之server开始启动,从而伴随service下的containtor和connetor开始启动,待组件容器启动后,await()等待请求的到来

public void start() {

    // Start the new server
    try {
        getServer().start();
    } catch (LifecycleException e) {}


    // Register shutdown hook
    if (useShutdownHook) {
        if (shutdownHook == null) {
            shutdownHook = new CatalinaShutdownHook();
        }
        Runtime.getRuntime().addShutdownHook(shutdownHook);
    }


    if (await) {
        // 创建一个带有port和ip address的ServerSocket,等待请求的到来:serverSocket.accept()方法阻塞,直到请求的到来
        await();
        stop();
    }
}

同Server.init()方法一样,各个组件容器的start按照首先走LifecycleBase.start(),再走Server.startInternal()的模式逐一启动

LifecycleBase.start()

各个组件容器状态的变更同样都是在父类中通过事件驱动完成的

public final synchronized void start() throws LifecycleException {
    try {
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        // 调用子类的重载方法
        startInternal();
        setStateInternal(LifecycleState.STARTED, null, false);
        }
    } catch (Throwable t) {}
}

各个组件启动步骤与实例化步骤几乎一样,都是从外层组件逐一向内层推进,落实到代码上就是外层组件的start方法调用内层组件的start方法

Server.startInternal()代码如下

protected void startInternal() throws LifecycleException {
    fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    setState(LifecycleState.STARTING);

    // Start our defined Services
    synchronized (servicesLock) {
        for (int i = 0; i < services.length; i++) {
            services[i].start();
        }
    }
}

Service.startInternal()代码如下

protected void startInternal() throws LifecycleException {


    // 变更状态,发布事件
    setState(LifecycleState.STARTING);


    // Start our defined Container first
    if (container != null) {
        synchronized (container) {
            // container:StandardEngine
            // 逐一启动engine,host,context,warpper
            container.start();
        }
    }


    // 默认没有
    synchronized (executors) {
        for (Executor executor: executors) {
            executor.start();
        }
    }


    // Start our defined Connectors second
    synchronized (connectorsLock) {
        for (Connector connector: connectors) {
            try {
                connector.start();
            } catch (Exception e) {}
        }
    }
}

container[StandardEngine].start()

protected synchronized void startInternal() throws LifecycleException {

    // Standard container startup
    // 接着启动 LockoutRealm,UserDataBaseRealm(查询tomcat-users.xml),pipeline
    super.startInternal();
}

connector.start()

根据具体的协议类型类

protected void startInternal() throws LifecycleException {


    // 变更生命周期状态
    setState(LifecycleState.STARTING);

    try {
        // 具体的协议类型类启动,如Http11Protocal启动
        protocolHandler.start();
    } catch (Exception e) {
    }

    // 获取旗下的engine、host、context、Wrapper并增加到listers中
    mapperListener.start();
}

Http11Protocal.start()

 public void start() throws Exception {

        try {
            // start JIoEndPoint
            endpoint.start();
        } catch (Exception ex) {

        }
    }

JIoEndPoint.startInternal()
JIoEndPoint处理到来的tcp连接,创建ThreadPoolExecutor

public void startInternal() throws Exception {
    if (!running) {
        if (getExecutor() == null) {
            // 根据MinSpareThreads、MaxThreads属性创建默认的ThreadPoolExecutor
            createExecutor();
        }

        // 创建n个Acceptor用于接收客户端请求
        startAcceptorThreads();
    }
}


public void createExecutor() {
    internalExecutor = true;
    TaskQueue taskqueue = new TaskQueue();
    TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
    // MinSpareThreads、MaxThreads属性可在server.xml中Connector元素处配置
    executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
    taskqueue.setParent( (ThreadPoolExecutor) executor);
}

protected final void startAcceptorThreads() {
    int count = getAcceptorThreadCount();
    acceptors = new Acceptor[count];


    // 创建count个Acceptor,每个对应一个线程thread,thread.start(),等待请求的到来
    for (int i = 0; i < count; i++) {
        acceptors[i] = createAcceptor();
        String threadName = getName() + "-Acceptor-" + i;
        acceptors[i].setThreadName(threadName);
        Thread t = new Thread(acceptors[i], threadName);
        t.setPriority(getAcceptorThreadPriority());
        t.setDaemon(getDaemon());
        t.start();
    }
}

mapperListener.start()

添加engine、host、context、Wrapper到listers中
public void startInternal() throws LifecycleException {
    // 变更状态
    setState(LifecycleState.STARTING);


    // Find any components that have already been initialized since the
    // MBean listener won't be notified as those components will have
    // already registered their MBeans
    // 获取host,从server.engine属性中获取,并验证DefaultHost
    findDefaultHost();


    Engine engine = (Engine) connector.getService().getContainer();
    addListeners(engine);


    Container[] conHosts = engine.findChildren();
    for (Container conHost : conHosts) {
        Host host = (Host) conHost;
        if (!LifecycleState.NEW.equals(host.getState())) {
            // Registering the host will register the context and wrappers
            registerHost(host);
        }
    }
}

server.await():等待请求的到来

public void await() {
    // Set up a server socket to wait on
    try {
        awaitSocket = new ServerSocket(port, 1,
                InetAddress.getByName(address));
    } catch (IOException e) {}


    try {
        awaitThread = Thread.currentThread();

        ServerSocket serverSocket = awaitSocket;


        try {
            socket = serverSocket.accept();
            socket.setSoTimeout(10 * 1000);  // Ten seconds
            stream = socket.getInputStream();
        } catch (SocketTimeoutException ste) {
        }



    }
}

关键类的简要说明:
conf/server.xml对应的类

<Connector port="8092" protocol="org.apache.coyote.http11.Http11NioProtocol"  
   URIEncoding="UTF-8" 
   enableLookups="false" 
   useBodyEncodingForURI="true" 

   connectionTimeout="20000" 
   maxThreads="1024" // JIoEndPoint.set***
   minSpareThreads="256" // JIoEndPoint.set***
   />
tomcat性能基本上就取决于Tomcat处理HTTP请求的connector模块的性能,所以熟悉connector就尤为重要,了解connector各个属性特点就为之必然
各属性的作用和使用位置介绍:


enableLookups(默认false):The "enable DNS lookups" flag for this Connector.


useBodyEncodingForURI(默认false):URI encoding as body,如果为ture,url?后的参数编码(encoding)设置为和body一样的


abstractProtocol属性:
connectionTimeout(默认60000ms):
maxThreads(默认200):Maximum amount of worker threads ,会赋值给abstractEndpoint的maxThreads
minSpareThreads(默认10):
注:创建ThreadPoolExecutor对象也会用到maxThreads、minSpareThreads
例:new ThreadPoolExecutor(int minSpareThreads, int maxThreads, ...)

四、tomcat处理一个请求过程分析

一个请求过程简要分析:

1. 接收到请求的serverSocket会被wrapper包装一下,之后放到线程池里面,由线程池分配一个线程来处理这个请求
2. Http11Processor解析http的请求,生产并封装requestresponse对象
3. 通过connector.getService()调用一系列的invoke(request,response)方法,传递requestresponse顺着Containter的Pipeline一直到StandardWrapperValve,在StandardWrapperValve中,创建FilterChain并执行,包括我们自己定义的,到我们的应用中,完成响应

当一个http请求到来的时候,AbstractEndpoint.Acceptor会接收这个请求,之后调用processSocket方法,从线程池中获取一个线程处理socket请求

protected class Acceptor extends AbstractEndpoint.Acceptor {


    @Override
    public void run() {


        int errorDelay = 0;


        while (running) {
            // Accept the next incoming connection from the server socket
            socket = serverSocketFactory.acceptSocket(serverSocket);

            if (running && !paused && setSocketOptions(socket)) {
                // Hand this socket off to an appropriate processor
                if (!processSocket(socket)) {
                    countDownConnection();
                    // Close socket right away
                    closeSocket(socket);
                }
            } 
        }


    }
}
// 调用本类的processSocket方法
protected boolean processSocket(Socket socket) {
        // Process the request from this socket
        try {
            // 把socket包装成SocketWrapper
            SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
            wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
            wrapper.setSecure(isSSLEnabled());
            // 从线程池中新起一个线程执行包装类
            getExecutor().execute(new SocketProcessor(wrapper));
        }
        return true;
    }

此时从线程池获取一个线程执行SocketProcessor,从而执行JIoEndpoint.SocketProcessor.run方法,而在run方法总会调用AbstractProtocol.AbstractConnectionHandler.process()方法处理socket

JIoEndpoint.SocketProcessor.run
public void run() {
    boolean launch = false;
    synchronized (socket) {
        try {
            if ((state != SocketState.CLOSED)) {
                if (status == null) {
                    // AbstractProtocol.AbstractConnectionHandler.process()
                    state = handler.process(socket, SocketStatus.OPEN_READ);
                } else {
                    state = handler.process(socket,status);
                }
            }
}

AbstractProtocol.AbstractConnectionHandler.process()方法,会根据请求的协议类型创建相应的类型处理类,协议类型的来源就是con/server.xml中connector元素的protocol属性值。我们这里配置的是HTTP/1.1,所以类型为Http11Protocol,接着调用其处理器AbstractHttp11Processor的process()方法继续处理包装socket的SocketeWrapper类,处理的目的是生成request和response对象

AbstractProtocol.AbstractConnectionHandler.process()
public SocketState process(SocketWrapper<S> wrapper,
            SocketStatus status) {


    wrapper.setAsync(false);
    ContainerThreadMarker.markAsContainerThread();


    try {
        if (processor == null) {
            processor = recycledProcessors.poll();
        }
        if (processor == null) {
            processor = createProcessor();
        }
        // 判断是否支持ssl
        initSsl(wrapper, processor);

        SocketState state = SocketState.CLOSED;
        do {
            // processor:AbstractHttp11Processor;wrapper:SocketeWrapper
            // Process pipelined HTTP requests using the specified input and output streams
            state = processor.process(wrapper);
        while (state == SocketState.ASYNC_END ||
                        state == SocketState.UPGRADING ||
                        state == SocketState.UPGRADING_TOMCAT);

    }catch(){}
}

下面这个方法主要用来处理request和response对象,(注意:这个request和response不是我们平时用的,这个是tomcat自己用的,但是我们熟悉的request和response的数据是从这里得到的),会赋一部分属性值,如severPort/name,uri,headers,接着通过CoyoteAdapter.service(req,res)方法进行req,res对象的操作

AbstractHttp11Processor.process

public SocketState process(SocketWrapper<Socket> socketWrapper)
        throws IOException {
    // 这个request和response是通过父类的构造方法new出来的
    RequestInfo rp = request.getRequestProcessor();
    rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);



    // Setting up the I/O
    setSocketWrapper(socketWrapper);
    getInputBuffer().init(socketWrapper, endpoint);
    getOutputBuffer().init(socketWrapper, endpoint);

    try {
        setRequestLineReadTimeout();


        // 解析request的serverPort/name,uri等信息
        if (!getInputBuffer().parseRequestLine(keptAlive)) {
            if (handleIncompleteRequestLineRead()) {
                break;
            }
        }


        if (endpoint.isPaused()) {

        } else {
            keptAlive = true;
            // Set this every time in case limit has been changed via JMX
            request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
            request.getCookies().setLimit(getMaxCookieCount());
            // Currently only NIO will ever return false here
            // 解析requset头信息
            if (!getInputBuffer().parseHeaders()) {
                // We've read part of the request, don't recycle it
                // instead associate it with the socket
                openSocket = true;
                readComplete = false;
                break;
            } 
        }
    }

    // Setting up filters, and parse some request headers,设置request.serverPort等
    prepareRequest();

    // Process the request in the adapter
    if (!getErrorState().isError()) {
        try {
            rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
            // adapter:CoyoteAdapter对参数赋值转化等操作
            adapter.service(request, response);

        } catch (InterruptedIOException e) {}
    }

下面这个方法会继续对req,res进行操作(这里会出现两个request和两个response,不同包下的同名,注意区分),最后会沿着Service的Pipeline管道调用Containtor(对应开头结构图)的invoke方法

CoyoteAdapter.service(request, response)

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


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


        if (request == null) {


            // Create objects
            //创建request:org.apache.catalina.connector.Request;response:org.apache.catalina.connector.Response对象
            request = connector.createRequest();
            request.setCoyoteRequest(req);
            response = connector.createResponse();
            response.setCoyoteResponse(res);


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


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


            // Set query string encoding
            req.getParameters().setQueryStringEncoding
                (connector.getURIEncoding());


        }


        if (connector.getXpoweredBy()) {
            response.addHeader("X-Powered-By", POWERED_BY);
        }


        boolean comet = false;
        boolean async = false;
        boolean postParseSuccess = false;


        try {
            // Parse and set Catalina and configuration specific
            // request parameters
            req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
            // 给req,res剩余的属性赋值,如proxyPort,sessionId,context属性
            postParseSuccess = postParseRequest(req, request, res, response);
            if (postParseSuccess) {
                //check valves if we support async
                request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
                // Calling the container
                // connector:Connector[HTTP/1.1-8080],调用org.apache.catalina.core.StandardEngineValve[Catalina].invoke(request, response)             
                //调用容器组件,沿着管道一直到wrapperValue
                connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
            }

            try {
                // 结束请求,回收资源
                request.finishRequest();
                response.finishResponse();


                request.recycle();
                response.recycle();
            }  
        }
    }





开始进入管道

StandardEngineValve[Catalina].invoke(req, res)

public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    // Select the Host to be used for this Request
    Host host = request.getHost();
    if (host == null) {
        response.sendError
            (HttpServletResponse.SC_BAD_REQUEST,
             sm.getString("standardEngine.noHost", 
                          request.getServerName()));
        return;
    }
    if (request.isAsyncSupported()) {
        request.setAsyncSupported(host.getPipeline().isAsyncSupported());
    }


    // Ask this Host to process this request
    // host.getPipeline().getFirst():org.apache.catalina.valves.AccessLogValve[localhost]
    host.getPipeline().getFirst().invoke(request, response);


}


AccessLogValve.invoke()
public void invoke(Request request, Response response) throws IOException,
        ServletException {
    // getNext()-->org.apache.catalina.valves.ErrorReportValve[localhost]
    getNext().invoke(request, response);
}


StandardHostValve.invoke(request, response)  
public final void invoke(Request request, Response response)
    throws IOException, ServletException {


    // Select the Context to be used for this Request
    Context context = request.getContext();

    try {
        if (!asyncAtStart || asyncDispatching) {
            // context:StandardEngine[Catalina].StandardHost[localhost].StandardContext[/yy]
            // context.getPipeline().getFirst():org.apache.catalina.authenticator.ValveBase
            context.getPipeline().getFirst().invoke(request, response);
        } else {
            // Make sure this request/response is here because an error
            // report is required.
            if (!response.isErrorReportRequired()) {
                throw new IllegalStateException(sm.getString("standardHost.asyncStateError"));
            }
        }
    } catch (Throwable t) {}






org.apache.catalina.authenticator.AuthenticatorBase extends ValveBase.invoke(request, response);
public void invoke(Request request, Response response)
        throws IOException, ServletException {


    if (log.isDebugEnabled())
        log.debug("Security checking request " +
            request.getMethod() + " " + request.getRequestURI());
    LoginConfig config = this.context.getLoginConfig();
    if (constraints == null && !context.getPreemptiveAuthentication()) {
        if (log.isDebugEnabled())
            log.debug(" Not subject to any constraint");
        // getNext():org.apache.catalina.core.StandardContextValve[/yy]
        getNext().invoke(request, response);
        return;
    }





StandardContextValve.invoke(request, response)
public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    // Acknowledge the request,设置钩子,等待服务器返回response
    try {
        response.sendAcknowledgement();
    } catch (IOException ioe) {


    // wrapper.getPipeline().getFirst():org.apache.catalina.core.StandardWrapperValve[jsp]
    wrapper.getPipeline().getFirst().invoke(request, response);








org.apache.catalina.core.StandardWrapperValveinvoke(request, response);
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++;
    StandardWrapper wrapper = (StandardWrapper) getContainer();
    Servlet servlet = null;
    Context context = (Context) wrapper.getParent();

    // 获取请求路径
    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
    ApplicationFilterFactory factory =
        ApplicationFilterFactory.getInstance();
    // 创建一个过滤链filterChain
    ApplicationFilterChain filterChain =
        factory.createFilterChain(request, wrapper, servlet);


    // Call the filter chain for this request
    // NOTE: This also calls the servlet's service() method
    //会走我们的filter,获取我们熟悉的request和response:是javax.setvlet包下的
    try {
        filterChain.doFilter(request.getRequest(), response.getResponse());

filterChain.doFilter内部会调用HttpServlet.service(request, response),
ApplicationFilterChain.doFilter(javax.servlet.ServletRequest request,javax.servlet.ServletResponse response)

五、 .jsp生成.java和.class流程分析

这里直接借鉴牛人的讲述
www.zhihu.com/question/37…
文字我们虽然省略了,但是一定要跟着他的流程图,自己debug源码走一遍,边走边看信息,才能有直观的、深刻的感受和收获

六、 apache beachmark性能测试

官方自带配置性能:

//模拟1024个并发用户,对一个页面发送20000 个请求,其中-n代表请求数,-c代表并发数,官方解释
-c concurrency
Number of multiple requests to perform at a time. Default is one request at a time.
-n requests
Number of requests to perform for the benchmarking session. The default is to just perform a single request which usually leads to non-representative benchmarking results.


D:\httpd-2.4.23-win64-VC14\Apache24\bin>ab.exe -n 20000 -c 1024 http://localhost:8080/yy/test.jsp


This is ApacheBench, Version 2.3 <$Revision: 1748469 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/


Benchmarking localhost (be patient)
Completed 2000 requests
Completed 4000 requests
Completed 6000 requests
Completed 8000 requests
Completed 10000 requests
Completed 12000 requests
Completed 14000 requests
Completed 16000 requests
Completed 18000 requests
Completed 20000 requests
Finished 20000 requests




Server Software:        Apache-Coyote/1.1
Server Hostname:        localhost
Server Port:            8080


Document Path:          /yy/test.jsp
Document Length:        253 bytes //测试网页回应的网页大小
Concurrency Level:      1024 //并发数
Time taken for tests:   8.883 seconds //整个测试持续的时间
Complete requests:      20000
Failed requests:        0
Total transferred:      9840000 bytes //整个场景中的网络传输量,包含http的头信息等
HTML transferred:       5060000 bytes //整个场景中的 HTML 内容传输量,即html字节数,实际的页面传递字节数 
Requests per second:    2251.59 [#/sec] (mean) //每秒能处理的的请求数 =1000ms除以0.444
Time per request:       454.789 [ms] (mean) //每批请求处理完成的平均时间
Time per request:       0.444 [ms] (mean, across all concurrent requests) //每个请求处理完成的平均时间 =每批完成时间除以并发数(-c后的值),如454.789/1024
Transfer rate:          1081.82 [Kbytes/sec] received //每秒获取的数据长度


Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0  10.3      0     541
Processing:    52  396 393.5    228    2387
Waiting:       16  254 342.5    148    2346
Total:         52  396 393.9    228    2387
横轴的部分:
  ● min:    最小值
  ● mean:   平均值(正、负标准差)
  ● median: 平均值
  ● max:    最大值
纵轴的部分:
  ● Connect: 从ab发出TCP要求到Web主机所花费的建立时间
  ● Processing: 从TCP连线建立后,直到HTTP 回应(Response)的资料全部都收到所花的时间。
  ● Waiting: 从发送HTTP要求完后,到 HTTP 回应(Response)第一个Byte 所等待的时间。
  ● Total: 等于Connect + Processing 的时间(因为Waiting包含在Processing时间內了)

 //下面的内容为整个场景中所有请求的响应情况。在场景中每个请求都有一个响应时间,其中 50 % 的用户响应时间小于 228 毫秒, 60 % 的用户响应时间小于 273 毫秒,最大的响应时间小于 2387 毫秒
Percentage of the requests served within a certain time (ms)
  50%    228
  66%    273
  75%    326
  80%    785
  90%    806
  95%    919
  98%   1920
  99%   1953
 100%   2387 (longest request)

D:\httpd-2.4.23-win64-VC14\Apache24\bin>
参考资料:http://www.lai18.com/content/2587045.html
    原文作者:java集合源码分析
    原文地址: https://juejin.im/entry/58b253538fd9c50063d8d29b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞