Servlet是单例的

导读:本篇文章讲解 Servlet是单例的,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

单例模式的定义

狭义:一个类有且仅有一个实例(把构造器定义为私有的(private),这样其他人就没法new出它的实例了,当然,反射和序列化的漏洞需要进一步处理),且自行实例化向整个系统提供

广义:只要满足在整个系统中仅有一个实例,就认为它是单例

Servlet 3.1 规范

原文

2.2 Number of Instances
The servlet declaration which is either via the annotation as described in Chapter 8,
“Annotations and pluggability” or part of the deployment descriptor of the Web
application containing the servlet, as described in Chapter 14, “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.

翻译

2.2 实例数量
通过注解描述的(第 8 章 注解和可插拔性)或者在 Web 应用程序的部署描述符(第 14 章 部署描述符)
中描述的 servlet 声明,控制着 servlet 容器如何提供 servlet 实例。
对于未托管在分布式环境中(默认)的 servlet 而言,servlet 容器对于每一个 Servlet 声明必须且只能产生一
个实例。不过,如果 Servlet 实现了 SingleThreadModel 接口,servlet 容器可以选择实例化多个实例以便处
理高负荷请求或者串行化请求到一个特定实例。
如果 servlet 以分布式方式进行部署,容器可以为每个虚拟机(JVM)的每个 Servlet 声明产生一个实例。但
是,如果在分布式环境中 servlet 实现了 SingleThreadModel 接口,此时容器可以为每个容器的 JVM 实例化
多个 Servlet 实例。

按照Servlet 3.1 规范中的定义,当Servlet没有实现 SingleThreadModel 接口时,Servlet才是单例的;
如果实现该接口,那么每次请求相同的Servlet,将会创建一个新的实例。
BeURne.png
现在有一个TestServlet,并没有实现SingleThreadModel接口,那么实例化它将执行HttpServlet的构造器。当然了,父类 GenericServlet 的构造器也会执行,而且它的构造器也是公有的。

如此看来,单例模式中的私有构造器与Servlet中的公有构造器明显匹配不上了

综上所述,还是偏向于广义上的范畴,只要满足在整个系统中仅有一个实例,就认为它是单例。

Servlet 容器

这里以 Tomcat 为例

Tomcat 实现了 Servlet 的规范,来提供 Servlet 实例,而 Tomcat 里执行实例化Servlet的类叫StandardWrapper,它有个 loadServlet 的方法

/**
* Load and initialize an instance of this servlet, if there is not already
* at least one initialized instance.  This can be used, for example, to
* load servlets that are marked in the deployment descriptor to be loaded
* at server startup time.
* @return the loaded Servlet instance
* @throws ServletException for a Servlet load error
*/
public synchronized Servlet loadServlet() throws ServletException {

    // Nothing to do if we already have an instance or an instance pool
    if (!singleThreadModel && (instance != null)){
        return instance;
    }

    // 略
    // 
}

可以看到,该方法是同步的(synchronized修饰符)。 如果实现了之前说到的 SigleThreadModel 接口,那么这里的 singleThreadModel 就是true,就不会因为有Servlet实例而返回原有的Servlet了。

Tomcat是通过反射来实例化Servlet的。它先根据web.xml(或者起相同作用的@WebServlet)找到***ServletClass的全路径类名***,然后通过类加载器得到Class对象,由Class对象取到构造器,通过构造器实例化ServletClass。

Servlet容器 默认是采用单实例多线程的方式处理多个请求的

  1. 当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在一个Servlet实例)
  2. 容器初始化化Servlet主要就是读取配置文件(例如tomcat,可以通过servlet.xml的设置线程池中线程数目,初始化线程池通过web.xml,初始化每个参数值等等。
  3. 当请求到达时,Servlet容器通过调度线程(Dispatchaer Thread) 调度它管理下线程池中等待执行的线程(Worker Thread)给请求者;
  4. 线程执行Servlet的service方法;
  5. 请求结束,放回线程池,等待被调用;
    (注意:避免使用实例变量(成员变量),因为如果存在成员变量,可能发生多线程同时访问该资源时,都来操作它,照成数据的不一致,因此产生线程安全问题)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69750.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!