`
liudeh_009
  • 浏览: 242736 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

解析Tomcat处理请求的类Connector<一>

阅读更多

       Connector类的相关配置在Tomcat的安装目录conf下的Server.xml文件里,我这次主要解析采用NIO方式处理请求的情况.在Server.xml的配置如下:

 

    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
               connectionTimeout="20000"
               redirectPort="8443" />

 

在tomcat启动的时候,会调用Connector类的Start()方法,根据以上配置,Connector的start方法里会调用Http11NioProtocol类的start()方法,如下:

  

 try {
            protocolHandler.start();
        } catch (Exception e) {
            String errPrefix = "";
            if(this.service != null) {
                errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
            }

            throw new LifecycleException
                (errPrefix + " " + sm.getString
                 ("coyoteConnector.protocolHandlerStartFailed", e));
        }

   Http11NioProtocol类的start()方法又会调用NioEndpoint类的start()方法,如下:

   

 try {
            ep.start();
        } catch (Exception ex) {
            log.error(sm.getString("http11protocol.endpoint.starterror"), ex);
            throw ex;
        }

 

    NioEndpoint类的start()方法如下:

   

public void start()
        throws Exception {
        // Initialize socket if not done before
        if (!initialized) {
            init();
        }
        if (!running) {
            running = true;
            paused = false;
            
            // Create worker collection
            if (getUseExecutor()) {
                if ( executor == null ) {
                    TaskQueue taskqueue = new TaskQueue();
                    TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-");
                    executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
                    taskqueue.setParent( (ThreadPoolExecutor) executor, this);
                }
            } else if ( executor == null ) {//avoid two thread pools being created
                workers = new WorkerStack(maxThreads);
            }

            // Start poller threads轮询线程的个数,默认等译cpu的个数
            pollers = new Poller[getPollerThreadCount()];
            for (int i=0; i<pollers.length; i++) {
                pollers[i] = new Poller();
                Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                pollerThread.setPriority(threadPriority);
                pollerThread.setDaemon(true);
                pollerThread.start();
            }

            // Start acceptor threads
            for (int i = 0; i < acceptorThreadCount; i++) {
                Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);
                acceptorThread.setPriority(threadPriority);
                acceptorThread.setDaemon(daemon);
                acceptorThread.start();
            }
        }
    }

    该方式初始化了处理接受Sockt的线程Acceptor,轮询sockt的线程Poller,真正处理socket的线程池executor 或workers.Acceptor类的run方法如下:

 

public void run() {
            // Loop until we receive a shutdown command
            while (running) {
                // Loop if endpoint is paused
                while (paused) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }
                try {
                    // Accept the next incoming connection from the server socket
                    SocketChannel socket = serverSock.accept();
                    // Hand this socket off to an appropriate processor
                    //TODO FIXME - this is currently a blocking call, meaning we will be blocking
                    //further accepts until there is a thread available.
                    if ( running && (!paused) && socket != null ) {
                        //processSocket(socket);
                        if (!setSocketOptions(socket)) {//把sockt交给poller数组
                            try {
                                socket.socket().close();
                                socket.close();
                            } catch (IOException ix) {
                                if (log.isDebugEnabled())
                                    log.debug("", ix);
                            }
                        } 
                    }
                }catch (SocketTimeoutException sx) {
                    //normal condition
                }catch ( IOException x ) {
                    if ( running ) log.error(sm.getString("endpoint.accept.fail"), x);
                } catch (OutOfMemoryError oom) {
                    try {
                        oomParachuteData = null;
                        releaseCaches();
                        log.error("", oom);
                    }catch ( Throwable oomt ) {
                        try {
                            try {
                                System.err.println(oomParachuteMsg);
                                oomt.printStackTrace();
                            }catch (Throwable letsHopeWeDontGetHere){}
                        }catch (Throwable letsHopeWeDontGetHere){}
                    }
                } catch (Throwable t) {
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }
            }//while
        }//run

 

      setSocketOptions(Socket socket)如下:

      

           

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

            NioChannel channel = nioChannels.poll();
            if ( channel == null ) {
                // SSL setup
                if (sslContext != null) {
                    SSLEngine engine = createSSLEngine();
                    int appbufsize = engine.getSession().getApplicationBufferSize();
                    NioBufferHandler bufhandler = new NioBufferHandler(Math.max(appbufsize,socketProperties.getAppReadBufSize()),
                                                                       Math.max(appbufsize,socketProperties.getAppWriteBufSize()),
                                                                       socketProperties.getDirectBuffer());
                    channel = new SecureNioChannel(socket, engine, bufhandler, selectorPool);
                } else {
                    // normal tcp setup
                    NioBufferHandler bufhandler = new NioBufferHandler(socketProperties.getAppReadBufSize(),
                                                                       socketProperties.getAppWriteBufSize(),
                                                                       socketProperties.getDirectBuffer());

                    channel = new NioChannel(socket, bufhandler);
                }
            } else {                
                channel.setIOChannel(socket);
                if ( channel instanceof SecureNioChannel ) {
                    SSLEngine engine = createSSLEngine();
                    ((SecureNioChannel)channel).reset(engine);
                } else {
                    channel.reset();
                }
            }
            //将socket注册到Poller的Selector上
            getPoller0().register(channel);
        } catch (Throwable t) {
            try {
                log.error("",t);
            }catch ( Throwable tt){}
            // Tell to close the socket
            return false;
        }
        return true;
    }

 getPoller0()方法如下:

  

    public Poller getPoller0() {
        int idx = Math.abs(pollerRotater.incrementAndGet()) % pollers.length;
        return pollers[idx];
    }

 Poller的register()方法如下:

    

       public void register(final NioChannel socket)
        {
            socket.setPoller(this);
            KeyAttachment key = keyCache.poll();
            final KeyAttachment ka = key!=null?key:new KeyAttachment();
            ka.reset(this,socket,getSocketProperties().getSoTimeout());
            PollerEvent r = eventCache.poll();
            ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
            if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
            else r.reset(socket,ka,OP_REGISTER);
            addEvent(r);//将sockt注册到Poller的队列中
        }

  addEvent()方法如下:

     

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

 

  Poller的run()方法如下:

        

 public void run() {
            // Loop until we receive a shutdown command
            while (running) {
                try {
                    // Loop if endpoint is paused
                    while (paused && (!close) ) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            // Ignore
                        }
                    }
                    boolean hasEvents = false;

                    hasEvents = (hasEvents | events());//往Selector注册Socket事件
                    // Time to terminate?
                    if (close) {
                        timeout(0, false);
                        break;
                    }
                    int keyCount = 0;
                    try {
                        if ( !close ) {
                            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) {
                            timeout(0, false);
                            selector.close(); 
                            break; 
                        }
                    } catch ( NullPointerException x ) {
                        //sun bug 5076772 on windows JDK 1.5
                        if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x);
                        if ( wakeupCounter == null || selector == null ) throw x;
                        continue;
                    } catch ( CancelledKeyException x ) {
                        //sun bug 5076772 on windows JDK 1.5
                        if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x);
                        if ( wakeupCounter == null || selector == null ) throw x;
                        continue;
                    } catch (Throwable x) {
                        log.error("",x);
                        continue;
                    }
                    //either we timed out or we woke up, process events first
                    if ( keyCount == 0 ) hasEvents = (hasEvents | events());

                    Iterator iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null;
                    // Walk through the collection of ready keys and dispatch
                    // any active event.
                    while (iterator != null && iterator.hasNext()) {
                        SelectionKey sk = (SelectionKey) iterator.next();
                        KeyAttachment attachment = (KeyAttachment)sk.attachment();
                        // Attachment may be null if another thread has called
                        // cancelledKey()
                        if (attachment == null) {
                            iterator.remove();
                        } else {
                            attachment.access();
                            iterator.remove();
                            processKey(sk, attachment);//将Socket交由线程池executor 或workers处理
                        }
                    }//while

                    //process timeouts
                    timeout(keyCount,hasEvents);
                    if ( oomParachute > 0 && oomParachuteData == null ) checkParachute();
                } catch (OutOfMemoryError oom) {
                    try {
                        oomParachuteData = null;
                        releaseCaches();
                        log.error("", oom);
                    }catch ( Throwable oomt ) {
                        try {
                            System.err.println(oomParachuteMsg);
                            oomt.printStackTrace();
                        }catch (Throwable letsHopeWeDontGetHere){}
                    }
                }
            }//while
            synchronized (this) {
                this.notifyAll();
            }
            stopLatch.countDown();

        }

 

       后续就是处理sockt请求,返回处理结果到浏览器端

0
0
分享到:
评论

相关推荐

    解析Tomcat处理请求的类Connector<三>

    【标题】:“解析Tomcat处理请求的类Connector&lt;三&gt;” 在Java的Web服务器领域,Tomcat无疑是最为广泛使用的轻量级应用服务器之一。它以其开源、免费、高效的特点深受开发者喜爱。在这个系列的第三部分,我们将深入...

    tomcat概述和体系架构

    在结构上,Tomcat的顶层类元素包括`&lt;Server&gt;`和`&lt;Service&gt;`,连接器类元素负责通信接口,而容器类元素则分为`Engine`、`Host`和`Context`,它们分别负责处理请求、特定虚拟主机请求和特定Web应用请求。所有的Tomcat...

    Tomcat 配置详解

    本文将详细解析Tomcat的核心配置元素,包括`&lt;Server&gt;`、`&lt;Service&gt;`、`&lt;Engine&gt;`、`&lt;Host&gt;`和`&lt;Context&gt;`,帮助读者更好地理解和优化Tomcat的运行环境。 首先,`&lt;Server&gt;`元素是Tomcat实例的顶级容器,由`org....

    Tomcat的server.xml文件

    4. `&lt;Engine&gt;`元素:`&lt;Engine&gt;`代表一个Servlet引擎,处理来自`&lt;Connector&gt;`的所有请求。`name`属性是引擎的名称,通常默认为`Catalina`。它还可以包含一个或多个`&lt;Host&gt;`元素,每个`&lt;Host&gt;`代表虚拟主机。 5. `...

    ssm黑马旅游整合最终版2018

    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;/dependency&gt; &lt;!-- 日志 --&gt; &lt;dependency&gt; &lt;groupId&gt;org.slf4j&lt;/groupId&gt; &lt;artifactId&gt;slf4j-log4j12&lt;/artifactId&gt; &lt;/dependency&gt; &lt;!-- 连接池 --&gt; ...

    tomcat服务器的配置详解

    3. **WEB SERVICE部分**:这部分由`&lt;Service&gt;`标签表示,定义了Tomcat的服务实例,每个服务可以包含多个`&lt;Connector&gt;`(监听端口)和`&lt;Engine&gt;`(处理HTTP请求)。`&lt;Connector&gt;`配置了Tomcat监听的IP地址和端口,...

    Tomcat的配置文件server.xml中各个域的说明及相关配置.pdf

    `&lt;Engine&gt;`可以包含多个`&lt;Host&gt;`元素,每个`&lt;Host&gt;`代表一个虚拟主机,处理特定域名下的请求。 然后,`&lt;Host&gt;`元素由`org.apache.catalina.Host`接口定义,它定义了虚拟主机的配置。`appBase`属性指定了虚拟主机的...

    Tomcat解析与性能优化.pdf

    - `&lt;Service&gt;` 元素:每个 `&lt;Service&gt;` 元素只能有一个 `&lt;Engine&gt;` 元素,处理所有 `&lt;Connector&gt;` 元素接收到的客户请求。 - `&lt;Engine&gt;` 元素:处理在同一 `&lt;Service&gt;` 中所有 `&lt;Connector&gt;` 元素接收到的客户请求...

    tomcat_server.xml_配置详解

    `&lt;Valve&gt;`是处理请求链中的一个环节,`className`定义Valve实现类。例如,`AccessLogValve`可记录应用程序的访问信息,`directory`、`pattern`等属性控制日志的输出和格式。 总结,`server.xml`配置文件是Tomcat的...

    tomcat结构分析

    `&lt;Service&gt;`元素不直接处理请求,它是一个或多个`&lt;Connector&gt;`和一个`&lt;Engine&gt;`的集合。每个`&lt;Service&gt;`都关联一个特定的`&lt;Engine&gt;`,用于处理所有传入的请求。 3. **Connector 组件** `&lt;Connector&gt;`组件是Tomcat...

    一个详细介绍tomcat6.0的内部结构的文档

    - `&lt;Engine&gt;` 元素是 `&lt;Service&gt;` 的子元素,它代表了 Tomcat 的“引擎”,负责处理 `&lt;Connector&gt;` 接收到的请求。 - `&lt;Engine&gt;` 组件可以包含一个或多个 `&lt;Host&gt;` 元素,每个 `&lt;Host&gt;` 对应一个虚拟主机。 5. **...

    tomcat server.xml元素详细说明

    `&lt;Service&gt;`元素用于定义服务,它将网络监听器(`&lt;Connector&gt;`)与请求处理器(`&lt;Engine&gt;`)关联起来,形成一个完整的网络服务。每个`&lt;Service&gt;`元素都有一个唯一的`name`属性,用于标识服务。 ### 3. &lt;Connector&gt; ...

    server.xml常用配置详解.docx

    每个 `&lt;Service&gt;` 只能包含一个 `&lt;Engine&gt;`,用于处理在同一 `&lt;Service&gt;` 中的所有 `&lt;Connector&gt;` 接收到的客户端请求,并将处理结果返回给 `&lt;Connector&gt;`。 - **支持的属性**:`&lt;Engine&gt;` 元素通常不会直接配置...

    Tomcat完整教程

    - `&lt;Service&gt;`:包含一个或多个`&lt;Connector&gt;`和一个`&lt;Engine&gt;`,处理特定服务的客户请求。 - `&lt;Connector&gt;`:处理服务器与客户端之间的通信。 - `&lt;Engine&gt;`:容器类元素,处理特定Service的所有请求,可以包含多...

    TOMCAT技术介绍.docx

    每个&lt;Service&gt;元素包含一个&lt;Connector&gt;,用于监听和处理网络连接,一个&lt;Engine&gt;用于处理特定Service的所有客户请求,以及多个&lt;Host&gt;,每个&lt;Host&gt;代表一个虚拟主机,可以包含多个&lt;Context&gt;,每个&lt;Context&gt;对应一个Web...

    SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)

    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;5.1.37&lt;/version&gt; &lt;/dependency&gt; &lt;!-- 日志相关 --&gt; &lt;dependency&gt; &lt;groupId&gt;log4j&lt;/groupId&gt; &lt;artifactId&gt;log4j&lt;/artifactId&gt; &lt;version&gt;${log4j....

    tomcat_server.xml_配置详解.doc

    `&lt;Engine&gt;`元素表示一个请求处理机,负责接收和处理来自`&lt;Connector&gt;`的请求。关键配置包括: - **defaultHost**:指定默认处理请求的主机名,需与某`&lt;Host&gt;`元素的`name`属性匹配。 ### 5. &lt;Host&gt; 元素:虚拟主机...

    tomcat-server.xml详解

    `&lt;Engine&gt;`元素是请求处理引擎,负责接收来自`Connector`的请求并分发给相应的`Host`。`defaultHost`属性指定了未明确指定主机名时的默认处理主机。`&lt;Host&gt;`元素代表虚拟主机,`name`属性定义了主机名,`appBase`...

    基于IDEA的ssm(spring+springMVC+mybatis)基本框架

    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;8.x.x&lt;/version&gt; &lt;/dependency&gt; &lt;!-- Servlet & JSTL for view rendering --&gt; &lt;dependency&gt; &lt;groupId&gt;javax.servlet&lt;/groupId&gt; &lt;artifactId&gt;javax....

    Spring+SpringMVC+Mybatis框架整合例子

    SpringMVC是Spring框架的一部分,专门用于处理Web请求,它将模型、视图和控制器分离,让代码结构更加清晰,易于维护。Mybatis则是一款优秀的持久层框架,它简化了数据库操作,通过XML或注解方式灵活配置SQL,实现了...

Global site tag (gtag.js) - Google Analytics