JavaWeb-07
JavaWeb-tomcat与web程序结构与Http协议与Servlet基础
HTTP协议(记住)
1、http协议:规定了客户端和服务端交流时的数据格式
a. WEB浏览器与WEB服务器之间的一问一答的交互过程必须遵循一定的规则,这个规则就是HTTP协议。
b. HTTP是HyperText Transfer Protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程及数据本身的格式。
c. HTTP协议的版本:HTTP/1.0、HTTP/1.1
d. HTTP协议是学习JavaWEB开发的基石,不深入了解HTTP协议,就不能说掌握了WEB开发,更无法管理和维护一些复杂的WEB站点。
2、HTTP1.0的基本运行方式
基于HTTP协议的客户/服务器模式的信息交换过程,如图所示,
它分四个过程:
建立连接、发送请求信息、发送响应信息、关闭连接。
浏览器与WEB服务器的连接过程是短暂的,每次连接只处理一个请求和响应。对每一个页面的访问,浏览器与WEB服务器都要建立一次单独的连接。
浏览器到WEB服务器之间的所有通讯都是完全独立分开的请求和响应。
无状态
3、HTTP1.0特点:
客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求。
一个完整的HTTP请求包括如下内容:
一个请求行、若干消息头、以及请求正文,其中的一些消息头和正文都是可选的,消息头和正文内容之间要用空行隔开。
1、请求和响应都由三部分组成:
请求信息(3部分组成):
1)请求行 (由3部分组成)
a) 请求的方式
b) 请求的资源地址
c) 请求协议
2)请求头信息(2部分组成)
a) 头名称
b) 头值
3)请求正文 (只有请求的类型是post才会有)
响应信息:(3部分组成)
1)响应行(由3部分组成)
a)响应协议
b)状态码
c)状态信息
2) 响应头信息(2部分):
a): 响应头
b): 头值
3) 响应正文.
2、get和post方式区别:
GET方式:如请求方式为GET方式,则可以在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔,例如:
GET /mail/1.html?name=abc&password=xyz HTTP/1.1
GET方式的特点:在URL地址后附带的参数是有限制的,其数据容量通常不能超过1K。
POST方式:如请求方式为POST方式,则可以在请求的正文内容中向服务器发送数据,Post方式的特点:传送的数据量无限制。
get方式对提交的数据大小有限制(1k),post方式对数据大小没有限制.
3、响应的状态码:
200(正常)
表示一切正常,返回的是正常请求结果
302/307(临时重定向)
指出被请求的文档已被临时移动到别处,此文档的新的URL在Location响应头中给出。
304(未修改)
表示客户机缓存的版本是最新的,客户机可以继续使用它,无需到服务器请求。
404(找不到)
服务器上不存在客户机所请求的资源。
500(服务器内部错误)
服务器端的程序发生错误
4、请求头信息:
* Accept: 浏览器告诉服务端, 浏览器可接受的MIME类型
* MIME类型: 相当于操作系统下的文件类型。
是由大类型和小类型组成: text/html;
对应的关系在conf/web.xml中查询
* Accept-Charset: 浏览器告诉服务端, 浏览器支持哪种字符集
* Accept-Encoding: 浏览器告诉服务端, 浏览器能够进行解码的数据编码方式,比如gzip
* Accept-Language: 浏览器告诉服务端,浏览器支持的语言种类
* Host: 浏览器告诉服务端,浏览器所在的主机
* Referer: 浏览器告诉服务端,当前页面从哪里来的。
*
用处:
1. 用来记录广告的信息
2. 防盗链
* Content-Type: 浏览器告诉服务端 ,内容类型 If-Modified-Since: 浏览器告诉服务端修改的时间
* Content-Length: 浏览器告诉服务端 请求正文内容长度
* Connection: 浏览器告诉服务端,连接的状态
* Cookie: 浏览器告诉服务端 ,浏览器携带的Cookie
* Date: 浏览器告诉服务端,发送请求的时间
5、响应头信息
*Location : 服务端用来告诉浏览器,请求需要重定向.(必须结合状态码302使用)
*Server : 服务端用来告诉浏览器,服务器的类型
*Content-Encoding: 服务端用来告诉浏览器,服务器对数据采用的编码
*Content-Length: 服务端用来告诉浏览器,响应正文的长度
*Content-Language: 服务端用来告诉浏览器,zh-cn服务发送的文本的语言
*Content-Type: 服务端用来告诉浏览器,你要用哪个码表来解析二进制数据
*Last-Modified : 服务端用来告诉浏览器,访问资源的最后修改时间
*Refresh:服务端用来告诉浏览器,多长时间刷新一次
*Content-Disposition: 服务端用来告诉浏览器,以下载文件的方式打开文件
*Expires: -1 : 服务端用来告诉浏览器,不要缓存 Cache-Control: no-cache (1.1) Pragma: no-cache (1.0)
*Set-Cookie: 服务端用来告诉浏览器,要存储的内容
以下我们使用httpwatch插件安装到IE浏览器去抓取客户端浏览器与tomcat服务器互访的数据包信息:
安装后
在MyEclipse下新建工程:
然后自定义配置工程的服务器。我们的实验使用的是tomcat服务器:
在此我们使用的是Tomcat6.x版本的,因为该版本可以兼容1.6版本以下的JDK: 在打开配置对话框后选择用户Tomcat存储的地址,然后点击apply再确定:
然后点击Tomcat6.x下的JDK选择用户JDK存储的目录:
确定完步骤之后,点击项目部署按钮:
进入部署界面,把新建的servlet项目绑定到自定义的服务器上,点击完redepoly之后下面对话框会显示成功,点击确定:
部署成功。
ServletResponse1.java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//演示location响应头
public class ServletResponse1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setStatus(302) ;
response.setHeader("Location", "/day07_01_httpresponse/servlet/ServletResponse2") ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
ServletResponse2.java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletResponse2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().write("hello world!!!") ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在装了httpwatch插件的IE里输入:http://localhost:8080/day0701httpresponse/servlet/ServletResponse1之后IE会自动跳转到了http://localhost:8080/day0701httpresponse/servlet/ServletResponse2
ServletResponse3.java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//演示content-Encoding响应头
public class ServletResponse3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ;
byte[] bs = s.getBytes() ;
System.out.println("压缩前的长度: " + bs.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
//用压缩流将数据压缩到一个输出流中
GZIPOutputStream out = new GZIPOutputStream(baos) ;
//将数据压缩到baos中
out.write(bs) ;
out.close() ;
//从输出流中拿取数据
bs = baos.toByteArray() ; // 拿取到了压缩后的数据
System.out.println("压缩后长度:" + bs.length);
//通知浏览器服务端采用的数据格式
response.setHeader("Content-Encoding", "gzip") ;
response.getOutputStream().write(bs) ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在装了httpwatch插件的IE里输入:http://localhost:8080/day0701httpresponse/servlet
/ServletResponse3
ServletResponse4
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//演示Content-Type响应头
public class ServletResponse4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//通知浏览器用哪个码表解析二进制数据
response.setHeader("Content-Type", "text/html;charset=gbk") ;
System.out.println(response.getCharacterEncoding()) ;
response.getWriter().write("冠希哥爱上了阿娇") ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在装了httpwatch插件的IE里输入:http://localhost:8080/day0701httpresponse/servlet
/ServletResponse4
ServletResponse6.java
import java.io.IOException;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//演示refresh响应头
public class ServletResponse6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//定期刷新自己
// response.setHeader("Refresh", "2") ;
// response.getWriter().write("aaaaaa" + new Random().nextInt()) ;
//刷新到其他页面
response.setHeader("Refresh", "2;url=/day07_01_httpresponse/servlet/ServletResponse5") ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在装了httpwatch插件的IE里输入:http://localhost:8080/day0701httpresponse/servlet
/ServletResponse6
点击打开后:
ServletResponse5.java
import java.io.FileInputStream;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//演示Content-Disposition响应头
public class ServletResponse5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取图片的路径
String path = getServletContext().getRealPath("/WEB-INF/classes/1.gif") ;
System.out.println(path);
//创建一个输入流
FileInputStream in = new FileInputStream(path) ;
//创建输出流
ServletOutputStream os = response.getOutputStream() ;
//通知浏览器以下载文件的方式来打开数据
response.setHeader("Content-Disposition", "attachment;filename=1.gif") ;
//读取数据发送数据
byte[] bs = new byte[1024] ;
int b = 0 ;
while((b = in.read(bs)) != -1){
os.write(bs,0,b) ;
}
in.close() ;
os.close() ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在装了httpwatch插件的IE里输入:http://localhost:8080/day0701httpresponse/servlet
/ServletResponse5
ServletResponse7.java
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//演示不要缓存
public class ServletResponse7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().write("hello ,ajiao") ;
response.setHeader("Expires", "-1") ;
response.setHeader("Cache-Control", "no-cache") ;
response.setHeader("Pragma", "no-cache") ;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在装了httpwatch插件的IE里输入:http://localhost:8080/day0701httpresponse/servlet
/ServletResponse7
Servlet
一、Servlet简介
Servlet是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
编写一个Java类,实现servlet接口。
把开发好的Java类部署到web服务器中。
- 快速入门,用servlet向浏览器输出“hello servlet”
阅读Servlet API,解决两个问题:
输出hello servlet的java代码应该写在servlet的哪个方法内? 如何向IE浏览器输出数据?
首先新建一个Java程序
把servlet的包拉到该路径下
在dos下进入到新建Java程序的文件夹内
设定classpath
设定好classpath之后编译java程序
得到类文件
配置新建工程下的web.xml文档
xml内容如下
工程环境配置好之后在客户端浏览器输入该路径,测试成功。
二、执行过程图解
Tomcat在加载Web应用时,就会把相应的web.xml文件中的数据读入到内存中。因此当Tomcat需要参考web.xml文件时,实际上只需要从内存中读取相关数据就可以了,无需再到文件系统中读取web.xml。
三、在Eclipse中开发Servlet
四、Servlet接口实现类
1、Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet、HttpServlet。
2、HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。
3、HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。
4、阅读HttpServlet API文档,看一下servlet-api.jar
五、Servlet的一些细节
1、由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用servlet标签和servlet-mapping标签完成。
2、servlet标签用于注册Servlet,它包含有两个主要的子元素:servlet-name标签和servlet-class标签,分别用于设置Servlet的注册名称和Servlet的完整类名。
一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:
<web-app>
<servlet>
<servlet-name>AnyName</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/demo/hello.html</url-pattern>
</servlet-mapping>
</web-app>
3、同一个Servlet可以被映射到多个URL上,即多个servlet-mapping标签的servlet-name标签子元素的设置值可以是同一个Servlet的注册名。
4、在Servlet映射到的URL中也可以使用通配符,但是只能有两种固定的格式:一种格式是“.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。
<servlet-mapping>
<servlet-name>
AnyName
</servlet-name>
<url-pattern>
*.do
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
AnyName
</servlet-name>
<url-pattern>
/action/*
</url-pattern>
</servlet-mapping>
5、如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
6、凡是在web.xml文件中找不到匹配的servlet-mapping标签的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
7、在tomcat的安装目录标签\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet。
8、当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。
六、Servlet的生命周期
1、 a. Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
b. 针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。
c. 在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。
2、如果在servlet标签中配置了一个load-on-startup标签,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
举例:
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
*用途:为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据。
注意:从提高Servlet容器运行性能的角度出发,Servlet规范为Servlet规定了不同的初始化情形。如果有些Servlet专门负责在 web应用启动阶段为web应用完成一些初始化操作,则可以让它们在web应用启动时就被初始化。对于大多数Servlet,只需当客户端首次请求访问时 才被初始化。假设所有的Servlet都在web应用启动时被初始化,那么会大大增加Servlet容器启动web应用的负担,而且Servlet容器有 可能加载一些永远不会被客户访问的Servlet,白白浪费容器的资源。
- 实验:
首先配置工程环境如下:
该工程下的web.xml文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<!-- com.heima.servlet.Servlet1 Servlet1 = new com.heima.servlet.Servlet1()-->
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-class>com.heima.servlet.Servlet1</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>Servlet2</servlet-name>
<servlet-class>com.heima.servlet.Servlet2</servlet-class>
<load-on-startup>6</load-on-startup>
</servlet>
<servlet>
<servlet-name>Servlet3</servlet-name>
<servlet-class>com.heima.servlet.Servlet3</servlet-class>
</servlet>
<servlet>
<servlet-name>Servlet4</servlet-name>
<servlet-class>com.heima.servlet.Servlet4</servlet-class>
</servlet>
<servlet>
<servlet-name>Servlet5</servlet-name>
<servlet-class>com.heima.servlet.Servlet5</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--
url的配置:
1. 配置的时候是以/开头,不允许/*.do 此种情况
2. 配置的时候是*开头,后面必须加后缀名
-->
<servlet-mapping>
<servlet-name>Servlet2</servlet-name>
<url-pattern>*.abcde</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet2</servlet-name>
<url-pattern>/aaa/bbb</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet3</servlet-name>
<url-pattern>/servlet/Servlet3</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet4</servlet-name>
<url-pattern>/servlet/Servlet4</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet5</servlet-name>
<url-pattern>/servlet/Servlet5</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Servlet1.java
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class Servlet1 extends GenericServlet {
public Servlet1() {
System.out.println("servlet1");
}
@Override
public void init() throws ServletException {
System.out.println("aaaaaaaaaaaaa");
}
// @Override
// public void init(ServletConfig config) throws ServletException {
// System.out.println("init方法");
// }
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
System.out.println("service");
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
Servlet2.java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
public class Servlet2 extends HttpServlet {
public Servlet2() {
System.out.println("bbbbbbbbbbbbbbbbb");
}
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
System.out.println("servletdemo2");
}
}
在服务器初始化时,输出以下代码,可以发现在xml文档里配置的
<servlet-name>Servlet1</servlet-name>
<servlet-class>com.heima.servlet.Servlet1</servlet-class>
<load-on-startup>2</load-on-startup>
起效了,效果图如下:
在配置完tomcat后打开浏览器输入http://localhost:8080/day0702servlet/servlet/Servlet1
得到如下结果:
service
七、线程安全
1、当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
2、如果某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。
3、SingleThreadModel接口中没有定义任何方法,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。
4、对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象。
5、实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过时的)。
结论:serlvet的线程安全(明白)
明确: Servlet的设计是一个单实例多线程。
线程安全要求将变量创建成一个局部变量,而不要创建成实例变量.
Servlet3.java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.SingleThreadModel;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//演示线程安全问题
//单实例多线程
public class Servlet3 extends HttpServlet implements SingleThreadModel {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int a = 0;
a++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(a);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
不断在浏览器内输入http://localhost:8080/day0702servlet/servlet/Servlet3
发现有以下反应: