HeadFirst Jsp 04 (请求和响应作为servlet)

servlet 的存在就是为了客服服务, servlet的任务是得到一个客户的请求, 再发回一个响应.

HeadFirst Jsp 04 (请求和响应作为servlet)

由上图可知, web 容器会在启动后就加载所有的servlet类, 并为之创建实例和初始化

注意: init方法是在第一个用户调用此servlet时被触发

service() 方法属于servlet类, 容器创建的线程调用了 service() 方法. 并把 HttpRequest, HttpReponse 这两个对象传递给了这个新的线程.

容器首先根据配置文件找到对应的 servlet, 然后 自然而然的调用这个servlet 的 service 方法, 那么就不用再确认调用的doPost是否弄错了, 比如调用了别人的servlet.

servlet 的继承关系

HeadFirst Jsp 04 (请求和响应作为servlet)

3大生命周期

HeadFirst Jsp 04 (请求和响应作为servlet)

HeadFirst Jsp 04 (请求和响应作为servlet)

HeadFirst Jsp 04 (请求和响应作为servlet)

HeadFirst Jsp 04 (请求和响应作为servlet)

一般 servlet 都不会有很多实例, 从这来看, 就一个实例

容器运行多个线程来处理对一个 servlet 的多个请求

对应每个客户请求, 会生成一对新的请求和响应对象.

注意:是容器根据请求中的url找到正确的servlet, 为这个请求创建分配了一个线程, 然后由这个线程调用

servlet的service()方法, 把请求和响应作为参数传给它.

HeadFirst Jsp 04 (请求和响应作为servlet)

容器是如何处理用户请求的?

1)用户点击一个链接,指向一个servlet而不是一个静态页面。

2)web服务器接到这个请求后转发给容器。容器接着创建两个对象:HttpServletRequest和HttpServletResponse。

3)容器根据请求中的URL找到相应的servlet,为这个请求创建一个线程,并把请求对象HtttpServletRequest和响应对象HttpServletResponse传递给这个servlet线程。

4)线程接下来调用service()方法,根据请求的不同,service()方法调用doGet()和doPost()方法。

5)doGet()方法生成动态页面,并把这个页面塞到响应对象里。

6)service()方法结束,随之线程结束,容器把响应对象装换为一个HTTP相应,发送给客户,然后删除请求和响应对象。

Servlet的生命周期

注意他的一生都是由容器控制的。servlet一生中只有一个实例出现,但是有多个线程出现。

加载类 Servlet .class文件

实例化 构造函数运行

初始化 容器调用 init() 方法(一生只调一次)

service方法? servlet一生主要在这里度过

销 毁? 销毁实例之前调用 destroy() 方法

可回收? 等待垃圾回收等待垃圾回收

servlet 在运行过程中, 变量的安全性问题

(一)变量的安全性

错误实例:

public class test extends HttpServlet{

String user = "" ;

public void doGet(HttpServletRequest req , HttpServletResponse res) throws ServletException , IOException{

user = req.getParameter("user");

......

}

}

例如:a、b同时访问这个servlet,a提交的user=aaa,b提交的user=bbb。

首先,servlet容器分配一个线程T-a来处理请求a,获取其user的值aaa,并赋给变量user。此时T-a时间片到了,servlet容器分配另外一个线程T-b来处理请求b,

获取其user的值bbb,并覆盖变量user,当T-a线程重新获取执行权时,user已经“物是人非”了。

因为user 是一个实例变量, 而这个实例(servlet) 一直都是“一个”实例,没有再增加, 所以他们调用的是同一个实例变量, 所以会有以上问题.

这里可以类比:jdbc的事务管理,“丢失更新”和这个场景类似。

解决方案:

1)定义本地变量,将user在doGet方法中定义。

因为user是本地变量,每一个线程都有user变量的拷贝,彼此不受影响。

2)设置方法同步(或者同步块)

因为设置了同步,可以防止多个线程同时调用doGet方法。但是所有请求该servlet的“请求”将串行处理,影响效率。同步实际是”排队”

HeadFirst Jsp 04 (请求和响应作为servlet)

幂等的定义: 一次一次可以重复执行的内容, doGet() 是幂等的, 可以返回执行, 而doPost()不是幂等的, 因为它可能修改服务器上的内容.

如何判定使用GET还是POST

Get: 简单的超链接. 默认使用Get,

Post: method=”post”, submit,

从请求对象中可以得到什么?

客户的平台浏览器信息

string client = request.getHeader(“User-Agent”);

与请求相关的cookie

Cookie[] cookies = request.getCookies();

与客户相关会话(session)

HttpSession session = request.getSession();

请求的HTTP方法

String theMethod = request.getMethod();

请求的输入流

InputStream input = request.getInputStream();


响应

响应要返回给客户, 这是浏览器得到, 解析并呈现给用户的东西, 一般你会使用响应对象得到一个输出流(通常是一个writer), 并使用这个流写出HTML(或其他类型内容), 返回给客户. ( 也可以生成一个jsp返回给客户 )

HeadFirst Jsp 04 (请求和响应作为servlet)

响应会经常调用两个方法:

setContentType()   // 告诉浏览器你发回去的是什么

getWriter()        // 用于输出字符

例如你要从服务器请求一个jar文件, 服务器的返回代码是:

public class CodeReturn extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws IOException, ServletException {

response.setContentType(“application/jar”);   // 告诉服务器返回内容的类型

ServletContext ctx = getServletContext();

InputStream is = ctx.getResourceAsStream(“/bookCode.jar”);

int read = 0;

byte[] bytes = new byte[1024];

OutputStream os = response.getOutputStream();

while ((read = is.read(bytes)) != -1) {

os.write(bytes, 0, read);

}

os.flush();

os.close();

}

}

对于输出, 你只有两个选择, 字节或字符

ServletOutputStream 输出字节

ServletOutputStream out = response.getOutputSt();

out.write(aByteArray);

PrintWriter 输出字符

PrintWriter writer = response.getWriter();

writer.println(“some text and HTML”);

利用重定向来响应, 而非servlet自己处理响应

利用jsp 来处理响应

HeadFirst Jsp 04 (请求和响应作为servlet)

HeadFirst Jsp 04 (请求和响应作为servlet)

重定向使得 servlet完全卸下担子, servlet只是调用 sendRedirect()方法:

response.sendRedirect(“http://www.abc.com”);   // 地址直接重定向

原路径: http://abc.com/myApp/cool/bar.do

response.sendRedirect(“foo/stuff.html”);       // 相对路径 = http://abc.com/myApp/cool/foo/stuff.html

reponse.sendRedirect(“/foo/stuff.html”);       // 绝对路径, 从根目录开始, 注意这是以”/”开头的, = http://abc.com/foo/stuff.html

请求分派

重定向让客户端完成工作 重定向 = 客户端

请求分派要求服务器上某某来完成任务 请求分配 = 服务器

HeadFirst Jsp 04 (请求和响应作为servlet)

上一篇:Python异步Socket编程


下一篇:私人定制javascript中对象小知识点(Only For Me)