1.Servlet 生命周期
Servlet 生命周期:Servlet加载—>实例化—>服务—>销毁。
1)init():在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。
当容器初始化一个servlet时,为其创建唯一的ServletConfig对象, 容器从DD中读取servlet初始化参数,并传给ServletConfig,然后 再将ServletConfig传给servlet的init()方法。
2)service():它是Servlet的核心,负责响应客户的请求。
每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
3)destroy(): 仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。
一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。
下图是servlet生命周期的简图。

2. Servlet线程和初始化
当Servlet容器中接受到多个请求时,容器是否为每个请求都会创建一个Servlet?
这样显然效率低,因此容器为单个servlet运行多个线程来处理多个请求。
如下图,就是两个客户都访问了同一个Servlet,容器并不是为每个用户创建一个servlet,而是为每个用户分配一个线程,并把请求和响应对象传给这个线程。

ServletConfig对象
每个servlet都有一个ServletConfig对象
用于向servlet传递部署时的信息
用于访问ServletContext
其参数在DD中配置
ServletContext
每个web应用都有一个ServletContext
用于访问web应用的参数(在DD中配置)
用于获取服务器信息
存放其它公用信息
3. Servlet工作原理
servlet没有main()方法,被容器控制。
容器将HTTP请求和响应传给servlet,并调用servlet上的方法,如 doPost()或doGet()
servlet工作原理


在第3步中,容器根据URL找到对应servlet,是怎么通过URL找到的呢?通过哪个URL呢?
一般一个servlet会有3个名字。
客户端名:URL 。类似 ……/register/registerMe部署名:
内部保密 。类似 EnrollServlet真实名:
文件 名。类似 SignUpServlet.class
客户端名 和 部署名 需要在DD文件中配置,接下来了解一下web应用的DD文件
3.1 web.xml配置文件
编写部署描述符文件web.xml,是web应用程序的署描述符文件(DD)
1 |
|
如上图,是一个DD文件的例子,从上图可以看出:
- 一个DD可以定义多个servlets
<servlet-name>
将<servlet>
元素绑定到<servlet-mapping>
元素<servlet-name>
对应于servlet的部署名,他是内部保密的<servlet-class>
是Java类 ,对应于servlet的真实名。<url-pattern>
是客户端用于请求servlet的名字,对用于servlet的客户端名。
4. HttpServletRequest对象和HttpServletResponse对象
web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象。通过request对象可以获取用户端提交的数据,通过response对象可以向客户端进行输出数据。
现在来了解Servlet的这两个对象:HttpServletResponse对象和HttpServletRequest对象。
4.1 HttpServletRequest对象
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象中的方法,可以获得客户的这些信息。
获取客户机环境信息常用的方法如下
1 | getRequestURL(); //返回客户端发出请求时的完整URL |
获取请求信息常用的方法
1 | /获得客户机请求头 |
Request对象还解决了一次请求内的不同Servlet的数据共享问题
可以通过setAttribute()
,将值放入到request对象,然后在前端页面使用getAttribute()
获取对应的值,这样就达到一次请求可以在多个页面共享一些对象信息
1 | request.setAttribute("name", "xxx"); // 在servlet中添加request参数 |
4.2 HttpServletResponse对象
HttpServletResponse对象是指服务器的响应,这个对象中封装了向客户端发送数据,发送响应头,发送响应状态码的方法。
下面是HttpServletResponse 以及 ServletResponse的类图,通过类图可以看出HttpServletResponse所提供的的方法,红色方框部分是获取一个输出流的方法,通过这个方法可以完成向客户端输出数据。

对于response对象的使用,首先需要setContentType()方法在响应的 HTTP头中设置MIME类型,告诉浏览器返回的是什么,浏览器就知道该怎么处理了。
1 | response.setContentType("text/html");//这里告诉浏览器返回的是text或者html |
使用响应对象获取一个输出流,使用输出 流向客户端写HTML
1 | PrintWriter out = response.getWriter(); |
下面是两个输出的例子。
1)向客户端输出中文数据
PrintWriter or ServletOutputStream
PrintWriter向字符流打印文本数据
1
2
3
4response.setContentType("text/html");
String data = "中国";
PrintWriter out = response.getWriter();
out.write(data);ServletOutputStream可以打印任何数据,如字节
1
2
3String data = "中国";
ServletOutputStream out = response.getOutputStream();
out.write(data.getBytes("UTF-8"));
2)输出文件下载
1 | public void doGet(HttpServletRequest request, HttpServletResponse response) |
5. Redirect vs. Request Dispatch
1)Redirect 原理
1 | response.sendRedirect("BrownBeer"); //sendRedirect(aString)方法的参数是String类型,而不是URL类型 |
当使用Redirect跳转页面时,servlet调用sendRedirect(aString), HTTP响应的状态码为301,Location 的头属性值是跳转的URL。

浏览器得到响应之后再次发起新的请求,之后按照正常的请求和响应方式显示页面。

2)Request Dispatch 原理
request对象提供了一个getRequestDispatcher方法,该方法返回一个RequestDispatcher对象,调用这个对象的forwoard方法可以实现请求转发。
1 | request.getRequestDispatcher("DarkBeer").forward(request, response); |
当使用Request Dispatch跳转页面时,通过forward(request, response)让跳转的jsp接管响应,最后返回给浏览器。这样浏览器的地址栏没有发生变化。

- Redirect使客户端执行转发,这样会使网页跳转频繁,影响用户体验。
- Request dispatch使服务器上的应用执行转发,浏览器地址栏没有变化,用户体验感好。