1、概述
狭义上看,是java的一个接口。
广义上看,任何直接或间接实现了Servlet接口的类。
2、核心对象
下面就是Servlet接口的内容:
public abstract interface javax.servlet.Servlet {
//初始化
public abstract void init(javax.servlet.ServletConfig arg0) throws javax.servlet.ServletException;
//部署时的配置信息,对应的是每个Servlet。
public abstract javax.servlet.ServletConfig getServletConfig();
//核心service方法,负责跳转到post或get方法中执行。
public abstract void service(javax.servlet.ServletRequest arg0, javax.servlet.ServletResponse arg1) throws javax.servlet.ServletException, java.io.IOException;
public abstract java.lang.String getServletInfo();
//销毁
public abstract void destroy();
}
Servlet的两个抽象类:
其中:
GenericServlet 抽象类实现了大部分的Servlet方法。
HttpServlet实现了一个service方法来反应servlet的http特性。
3、生命周期
servlet没有main方法,他们受控于一个java应用——容器。Servlet必须运行在web服务器中,web服务器也可以叫做web容器(比如tomcat)。二者是分工和互补的关系。web容器管理Servlet的生命周期,脱离web容器的Servlet便不能工作。
servlet的生命周期大致分为五部分:装载、实例化、init()、service()、destroy()。
首先,容器负责加载Servlet类,之后通过构造函数实例化servlet对象。在得到客户端servlet请求之前完成init()操作,之后是执行请求的service的方法。之后如果不再使用时,执行destroy方法。
得到servlet请求之后,tomcat并不把这个请求交给servlet本身,而是交给部署该servlet的容器。
此外,web容器还有其他的作用。比如:通信,支持多线程和jsp等等。
4、单实例,多线程。
一个web容器可以管理或存放多个servlet,比如:用户管理的servlet,商品管理的servlet等。
但对于提交到同一个servlet类的多个业务请求,共享一个servlet对象。比如:一个查询用户信息的请求和一个删除用户的请求共享同一个servlet对象。这就是所说的servlet单实例。
servlet体系结构是建立在java多线程机制之上的, servlet容器会自动使用线程池等技术来支持系统的运行。
思考:Servlet是线程安全的吗?
如果一句话回答安全或者不安全,这未免有些太过于笼统。
Servlet有三个作用域:上下文(Context)、会话(Session)和请求(request)。其中,前两个都是线程不安全的,只有在请求request中是线程安全的。
比较三个作用域:
名称 | 范围 | 特点 |
---|---|---|
上下文 | 相当于全局变量,范围最大 | 减少数据库操作,供所有用户 |
会话 | 会话范围,类似局部变量 | 每个用户享有自己信息 |
请求 | 范围在一次请求中 | 用完就扔 |
小结:
如果我们只是在请求的范围内,则不需要考虑线程安全的问题。除此之外,都会涉及到“共享变量”的问题,就要考虑如何实现线程安全了。其中最常用的方法是使用synchronized关键字,但要注意锁定的范围。如果在doPost()或doGet()方法上加synchronized,范围过大。servlet就变成了实实在在的单线程了,根本没办法处理并发,这样做虽然安全,但性能太差,也违背了servlet设计者的初衷,是绝对不可取的。加锁范围的思路是,如果此范围中你所操作的对象有可能被其他人访问到,那就加锁。