欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringMVC中DispatchServlet是单例还是多例(附源码分析)

程序员文章站 2023-04-03 17:14:50
一开始我只知道DispatchServlet是在web.xml中配置的,所以想当然的以为是单例,但结果和我预想的是有出入的。一、servlet规范因为DispatchServlet也是Servlet的一种,所以DispatchServlet和Servlet的表现结果应该相同。先贴上从网上找的servlet规范对于servlet实例个数的描述:“Deployment Descriptor”, controls how the servlet container provides instances...

一开始我只知道DispatchServlet是在web.xml中配置的,所以想当然的以为是单例,但结果和我预想的是有出入的。

一、servlet规范

因为DispatchServlet也是Servlet的一种,所以DispatchServlet和Servlet的表现结果应该相同。先贴上从网上找的servlet规范对于servlet实例个数的描述:

“Deployment Descriptor”, controls how the servlet container provides instances of the servlet.For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration. However, for a servlet implementing the SingleThreadModel interface, the servlet container may instantiate multiple instances to handle a heavy request load and serialize requests to a particular instance

“部署描述符”控制servlet容器如何提供servlet实例。 对于不在分布式环境中托管的servlet(默认设置),每个servlet声明中servlet容器 必须仅使用一个实例。 但是,对于实现SingleThreadModel接口的servlet, 该servlet容器可以实例化多个实例以处理繁重的请求负载并序列化对特定实例的请求。

答案已经有了:

  • 分布式系统下servlet实例的个数暂时不清楚;
  • 如果servlet实现了SingleThreadModel,则最多会创建20个实例;
  • 如果在web.xml中同一个servlet配置了多次,也会实例化多个实例;
  • 除了以上几种情况之外,servlet就是单例了。

源码分析:

在tomcat中,Servlet加载是在StandardWrapper中实现的,如下:

/**allocate()——>初始化实例方法,其中如果实现了SingleThreadModel接口,
    则会创建多个servlet实例,并将他们放到一个stack中。使用maxInstances属性来限制
    最大实例,默认是20个。*/
protected int maxInstances = 20;
public Servlet allocate() throws ServletException {
    ...
    synchronized(this.instancePool) {
    while(this.countAllocated.get() >= this.nInstances) {
        // 如果还没到20个,就继续创建
        if (this.nInstances < this.maxInstances) {
            try {
                // 放到栈中
                this.instancePool.push(this.loadServlet());
                ++this.nInstances;
            } catch (ServletException var7) {
                throw var7;
            } catch (Throwable var8) {
                ExceptionUtils.handleThrowable(var8);
                throw new ServletException(sm.getString("standardWrapper.allocate"), var8);
            }
        } else {
            try {
                this.instancePool.wait();
            } catch (InterruptedException var9) {
            }
        }
    }

    if (this.log.isTraceEnabled()) {
        this.log.trace("  Returning allocated STM instance");
    }

    this.countAllocated.incrementAndGet();
    return (Servlet)this.instancePool.pop();
}
    ...
}
loadServlet() 方法——>加载Servlet方法
public synchronized Servlet loadServlet() throws ServletException {
// 如果是单例,且不为空,直接返回,以下的感兴趣就看下,我没看。。。
        if (!this.singleThreadModel && this.instance != null) {
            return this.instance;
        } else {
            PrintStream out = System.out;
            if (this.swallowOutput) {
                SystemLogHandler.startCapture();
            }

            boolean var12 = false;

            Servlet servlet;
            try {
                var12 = true;
                long t1 = System.currentTimeMillis();
                if (this.servletClass == null) {
                    this.unavailable((UnavailableException)null);
                    throw new ServletException(sm.getString("standardWrapper.notClass", new Object[]{this.getName()}));
                }

                InstanceManager instanceManager = ((StandardContext)this.getParent()).getInstanceManager();

                try {
                    servlet = (Servlet)instanceManager.newInstance(this.servletClass);
                } catch (ClassCastException var13) {
                    this.unavailable((UnavailableException)null);
                    throw new ServletException(sm.getString("standardWrapper.notServlet", new Object[]{this.servletClass}), var13);
                } catch (Throwable var14) {
                    Throwable e = ExceptionUtils.unwrapInvocationTargetException(var14);
                    ExceptionUtils.handleThrowable(e);
                    this.unavailable((UnavailableException)null);
                    if (this.log.isDebugEnabled()) {
                        this.log.debug(sm.getString("standardWrapper.instantiate", new Object[]{this.servletClass}), e);
                    }

                    throw new ServletException(sm.getString("standardWrapper.instantiate", new Object[]{this.servletClass}), e);
                }

                if (this.multipartConfigElement == null) {
                    MultipartConfig annotation = (MultipartConfig)servlet.getClass().getAnnotation(MultipartConfig.class);
                    if (annotation != null) {
                        this.multipartConfigElement = new MultipartConfigElement(annotation);
                    }
                }

                if (servlet instanceof ContainerServlet) {
                    ((ContainerServlet)servlet).setWrapper(this);
                }

                this.classLoadTime = (int)(System.currentTimeMillis() - t1);
                if (servlet instanceof SingleThreadModel) {
                    if (this.instancePool == null) {
                        this.instancePool = new Stack();
                    }

                    this.singleThreadModel = true;
                }

                this.initServlet(servlet);
                this.fireContainerEvent("load", this);
                this.loadTime = System.currentTimeMillis() - t1;
                var12 = false;
            } finally {
                if (var12) {
                    if (this.swallowOutput) {
                        String log = SystemLogHandler.stopCapture();
                        if (log != null && log.length() > 0) {
                            if (this.getServletContext() != null) {
                                this.getServletContext().log(log);
                            } else {
                                out.println(log);
                            }
                        }
                    }

                }
            }

            if (this.swallowOutput) {
                String log = SystemLogHandler.stopCapture();
                if (log != null && log.length() > 0) {
                    if (this.getServletContext() != null) {
                        this.getServletContext().log(log);
                    } else {
                        out.println(log);
                    }
                }
            }

            return servlet;
        }
    }



本文地址:https://blog.csdn.net/StringBuff/article/details/108043322