Servlet本身只是一个Java,并不是单例结构,所以Servlet是不是单例最终取决于运行它的Web容器。
- 注解加载时默认是单例的。
- 如果一个Servlet没有被部署在分布式的环境中,一般web.xml中声明的一个Servlet只对应一个实例。
- 如果在web.xml中声明了几次,即使同一个Servlet,如果声明多次,也会生成多个实例。
Servlet容器默认是采用单实例多线程的方式处理多个请求的:
- 当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在一个Servlet实例);
- 容器初始化化Servlet主要就是读取配置文件(例如tomcat可以通过servlet.xml的设置线程池中线程数目)初始化每个参数值等等。
- 当请求到达时,Servlet容器通过调度线程(Dispatchaer Thread) 调度它管理下线程池中等待执行的线程(Worker Thread)给请求者;
- 线程执行Servlet的service方法;
- 请求结束,放回线程池,等待被调用;
注意:避免使用实例变量(成员变量
),因为如果存在成员变量,可能发生多线程同时访问该资源时,都来操作它,造成数据的不一致,因此产生线程安全问题。
只能说web容器对servlet实例化了一次。servlet只是一个普通的类,它也有自已的构造函数,甚至可以用new的方式new出N多个servlet的实例,但它能正常地处理web请求,就需要交给web服务器(或者叫servlet/jsp容器)来进行管理,比如说tomcat,tomcat通过配置文件获取映射信息,然后只会在第一次生成servlet的实例并把它缓存起来,下次再次请求,同样是取的这个实例,所以它的之前状态还是被保存起来的,所以共享的数据如果不是线程安全的,会出问题,所以别把数据用成员属性进行保存,别让servlet有状态。