zoukankan      html  css  js  c++  java
  • Tomcat从零开始(十七)——StandardWrapper

    第十七课:StandardWrapper

    课前复习:

           不知道大家是否还有印象,就是在67节课说的4container,粗略的从大到小来说就是engine,host,context,wrapper。当时写的时候很纠结,因为后面有详细介绍这4个的计划,所以前面写的可能不是很详尽。

           让我们回忆一下,当一个请求到来的时候,发生了什么。比如什么创建Request这里就不说了,之后connector会调用与之关联的容器的invoke方法,之后那就肯定会调用pipelineinvoke,之后一顿invoke valve。好,那让我们回想一下之前写过的contextwrapper,总结一个比较详细的执行过程。

    1.      Connector创建reqresp

    2.      调用StandardContextinvoke,调用xxxPipelineinvoke方法

    3.      Pipeline调用了wrapperinvoke方法

    4.      Wrapper调用valveinvoke方法

    5.      valve调用了servlet allocate(这里在以前的课程中讲过)

    6.      allocate方法调用servletload方法(servlet需要加载的时候)

    7.      init方法,之后就是servlet处理了。

    关于SingleThreadModel

           这个SingleThreadModelservlet2.4以上版本就已经移除了,因为这个东西只能给你的servletservice保证同一时刻只有一个进程在访问,给人一种假象的安全。而且只是给service方法给予同步,这显然是不能完全解决多线程访问的问题的。其实说这个是为了给下面的StandardWrapper做铺垫。因为我们都知道StrandardWrapper是负责加载它所代表的servletallocate一个对象的实例。之后交给valve来调用servletservice方法。这个allocate在使用不使用SingleThreadModel的时候是不同的。好的,我们接下来就说这个StandardWrapper

    StandardWrapper

           这个之前介绍过了,我们这次主要介绍的是allocate方法,我们看下面这一段源码可以发现,当没有实现SingleThreadModel的时候,allocate总是返回第一次时候产生的servlet实例。而如果实现SingleThreadModel接口,那么就开始控制分配的数量,当分配的大于nInstance时候,就load一个servlet实例,当然这个load实在maxInstance控制之内的。

           代码如下。

     

        public Servlet allocate() throws ServletException {
    
            if (debug >= 1)
                log("Allocating an instance");
    
            // If we are currently unloading this servlet, throw an exception
            if (unloading)
                throw new ServletException
                  (sm.getString("standardWrapper.unloading", getName()));
    
            // If not SingleThreadedModel, return the same instance every time
            if (!singleThreadModel) {
    
                // Load and initialize our instance if necessary
                if (instance == null) {
                    synchronized (this) {
                        if (instance == null) {
                            try {
                                instance = loadServlet();
                            } catch (ServletException e) {
                                throw e;
                            } catch (Throwable e) {
                                throw new ServletException
                                    (sm.getString("standardWrapper.allocate"), e);
                            }
                        }
                    }
                }
    
                if (!singleThreadModel) {
                    if (debug >= 2)
                        log("  Returning non-STM instance");
                    countAllocated++;
                    return (instance);
                }
    
            }
    
            synchronized (instancePool) {
    
                while (countAllocated >= nInstances) {
                    // Allocate a new instance if possible, or else wait
                    if (nInstances < maxInstances) {
                        try {
                            instancePool.push(loadServlet());
                            nInstances++;
                        } catch (ServletException e) {
                            throw e;
                        } catch (Throwable e) {
                            throw new ServletException
                                (sm.getString("standardWrapper.allocate"), e);
                        }
                    } else {
                        try {
                            instancePool.wait();
                        } catch (InterruptedException e) {
                            ;
                        }
                    }
                }
                if (debug >= 2)
                    log("  Returning allocated STM instance");
                countAllocated++;
                return (Servlet) instancePool.pop();
    
            }
    
        }

    Load

           这个没什么多说的,以前说过了,我们知道wrapper接口有一个load方法,其实他和Allocate里的一样,都是调用的LoadServlet方法。我们来看看它的源码。

        先看看这一段。

     

            // 这里是说如果不是第一次访问了,并且不是singleThreadModel
        	//就直接返回  Servlet实例
            if (!singleThreadModel && (instance != null))
                return instance;
    
    	if ((actualClass == null) && (jspFile != null)) {
                    Wrapper jspWrapper = (Wrapper)
                        ((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);
                    if (jspWrapper != null) {
                        actualClass = jspWrapper.getServletClass();
                        // Merge init parameters
                        String paramNames[] = jspWrapper.findInitParameters();
                        for (int i = 0; i < paramNames.length; i++) {
                            if (parameters.get(paramNames[i]) == null) {
                                parameters.put
                                    (paramNames[i], 
                                jspWrapper.findInitParameter(paramNames[i]));
                            }
                        }
                    }
    }
    
         这是Tomcat4 的方法,以后的版本就没有了。都是直接loadservletclass。之后就是Loader了,回忆一下我们当时讲的,是自定义的一个classLoader,需要注意的是,container提供一个特殊的servlet,可以访问container的内部内容,名称以org.apache.catalina.起始。之后就是加载servlet,之后就是权限验证,没啥说的。在之后就是在init()的前后fire事件。之后用instanceof来确定是否是实现了singleThreadModel的,如果是就放入pool(如果pool为空就创建一个新的)中。剩下就是Return了。



    ServletConfig

           接下来就是servletConfig,这个东西我们回忆一下是在哪里看到这个东西的,想想在servletload的时候,就会调用一个init方法,而且他的参数是ServletConfig config,那么,我们就需要知道servlet是怎么拿到servletConfig的,我们看源码,会发现StandardWrapper他实现了ServletConfig接口,所以说他把自己传过去就行了。但是想一个事情,如果这样可以,那么servlet的每一个实现就都可以用wrapper之内的方法了,wrappercontainer的,所以我们要保证安全,那么就像req,resp那样,用一个façade设计模式就行,这个就是隐藏子系统。

     

    Filter

           做过web开发,大家应该知道filter这个东西,那么filter是怎么实现的呢,我们想一下之前学的东西,我们应该能想到ServletWrapperValve做了这件事情,因为filter是跟service方法前后后关系。那么我们就可以知道valveinvoke方法做了什么:

    1.      首先要得到一个wrapper的对象,allocate一个servlet

    2.      来一系列的Filter,调用他们的doFilter方法,当然还有service方法

    3.      销毁,这个应该是在servlet超时的时候才进行。

    剩下就是讲解一下filterchain了,这个东西其实是一个ArrayList,但是注意filterChain是一个对象,其中的filter是一个该对象之中的一个arraylist,所以我们就知道,这个东西其实就是靠iterator来实现一个接一个的调用过滤器。所以,本章就结束了,这章其实没有多少自己写的东西,基本都是对源代码的一种分析,希望大家可以多理解,或者下一个tomcatsourcecode版本,之后多用断点 跑一跑就能理解是怎么工作的了。

        最后还是冒充一下大神说说读代码的事吧,刚才有人问了问为啥我能读懂一些,刚开始的时候我也看不懂,其实就是你最开始看的时候不要纠结于所有的语句,至少你能看懂这个方法主要是干啥功能的,大概哪几个语句能实现就行了,等你慢慢的看完这个,再看完另一个,你就能知道到底那个语句是干什么的了。

     

  • 相关阅读:
    cmd中编译java
    java出错
    去掉开始菜单中新装程序的红色标记【Windows】
    Windows安装java
    看视频缓冲好还一卡一卡【解决】
    python图像卷积
    电脑硬盘、内存
    python 查询Neo4j多节点的多层关系
    python 快速排序实现
    python 二分法实现
  • 原文地址:https://www.cnblogs.com/james1207/p/3367609.html
Copyright © 2011-2022 走看看