Servlet的基础体系
Servlet的运行过程
Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
1,Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第4步,否则,执行第2步。
2,装载并创建该Servlet的一个实例对象。
3,调用Servlet实例对象的init()方法。
4,创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
5,WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
Servlet生命周期
/**
* Servlet的声明周期:
* Servlet01() - 调用1次(服务器查询是否有该Servlet对象,没有就创建 --- 单例)
* init(ServletConfig config) - 调用1次(初始化数据的方法)
* 根据请求类型调用doGet()或doPost方法 - 前端发送1次请求就调用1次
* destroy() - 销毁方法,服务器销毁,该Servlet才会结束
*/
第一步:Servlet构造函数
public Servlet01() {
System.out.println("Servlet01构造方法");
}
第二步:init(ServletConfig config)
@Override
public void init(ServletConfig config) throws ServletException {
//获取匹配信息(配置信息可以在web.xml 或者 在注解里配置)
String code = config.getInitParameter("code");
System.out.println(code);
System.out.println("初始化 init方法");
}
第三步:调用doGet()/doPost()
//前端发送GET请求,服务器就就会调用doPost方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
//前端发送Post请求,服务器就会调用doPost()
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("接受到请求");
}
第四步:调用destroy()
@Override
public void destroy() {
System.out.println("Servlet01销毁方法");
}
service()和doGet()和doPost()方法的区别
/*1,service()既能处理get请求又能处理post请求,如果servlet中有service方法,会执行service()
2,doGet()只能处理get请求
3,doPost()只能处理post请求
注意:三个方法同时存在的情况下 首先执行srvice()
*/
方式一:web.xml
<servlet>
<servlet-name>Servlet01</servlet-name>
<servlet-class>com.ll.servlet.Servlet01</servlet-class>
<!--init-param 是初始化参数-->
<init-param>
<!--是参数名-->
<param-name>code</param-name>
<!--是参数值-->
<param-value>UTF-8</param-value>
</init-param>
<!-- 在项目启动的时候会被创建
注意:数字>=0,数字越小,优先级越高
-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--servlet-mapping 标签给 servlet 程序配置访问地址-->
<servlet-mapping>
<!--servlet-name 标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用-->
<servlet-name>Servlet01</servlet-name>
<!--url-pattern 标签配置访问地址 <br/>
/ 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径 <br/>
/Servlet01 表示地址为:http://ip:port/工程路径/Servlet01 <br/> -->
<url-pattern>/Servlet01</url-pattern>
</servlet-mapping>
</web-app>
方式二 注解
/** * @WebServlet - Servlet的注解 * value - url连接 * initParams - 初始化参数(数组) * @WebInitParam 初始化参数注解 * name - 参数名 * value - 参数值 * */
@WebServlet(value = "/Servlet02",
initParams = {
@WebInitParam(name = "code", value = "UTF-8")
},
loadOnStartup = 1
)
public class Servlet02 extends HttpServlet {
public Servlet02() {
System.out.println("Servlet02构造方法");
}
@Override
public void init(ServletConfig config) throws ServletException {
String code = config.getInitParameter("code");
System.out.println(code);
System.out.println("初始化 init方法 Servlet02");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet02接受到请求");
}
@Override
public void destroy() {
System.out.println("Servlet02销毁方法");
}
}
面试题
/* 面试题:Servlet何时被创建?
* 1.前端发送请求,服务器会查看是否有该Servlet对象,没有就创建
* 2.在web.xml中配置<load-on-startup>1</load-on-startup> 或者 在注解中配置 loadOnStartup = 1
* Servlet会在项目启动时被创建(注意:数组>=0,数字越小,优先级越高)
*/
ServletConfig对象
在Servlet的配置文件中,可以使用一个或多个标签为servlet配置一些初始化参数。
Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用。
Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对
象。
ServletConfig作用
1、可以获取 Servlet 程序的别名 servlet-name 的值
2、获取初始化参数 init-param
3、获取 ServletContext 对象
<!--init-param 是初始化参数-->
<init-param>
<!--是参数名-->
<param-name>code</param-name>
<!--是参数值-->
<param-value>UTF-8</param-value>
</init-param>
@Override public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("2 init 初始化方法");
// 1、可以获取 Servlet 程序的别名 servlet-name 的值
System.out.println("HelloServlet 程序的别名是:" + servletConfig.getServletName());
// 2、获取初始化参数 init-param
System.out.println("初始化参数 code 的值是;" + servletConfig.getInitParameter("code"));
// 3、获取 ServletContext 对象
System.out.println(servletConfig.getServletContext());
}
线程安全问题
出现原因
多个客户端访问同一个Servlet中的资源时,有可能会出现线程安全问题
出现问题案例
@WebServlet("/Servlet3")
public class Servlet03 {
private int num;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
num++;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resp.getWriter().println(num);
}
}
解决方案一
1.将Servlet实现SingleThreadModel(已过时),因为当线程阻塞,就会创建新的Servlet对象
@WebServlet("/Servlet3")
public class Servlet03 extends HttpServlet implements SingleThreadModel {
private int num;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
num++;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resp.getWriter().println(num);
}
}
解决方案二
利用线程锁机制, synchronized或lock
@WebServlet("/Servlet3")
public class Servlet03 extends HttpServlet {
private int num;
private Lock lock=new ReentrantLock();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
lock.lock();
num++;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resp.getWriter().println(num);
lock.unlock();
}
}
面试题
/**
* 面试题:Servlet是单例吗?
* 不一定,如果Servlet实现了SingleThreadModel接口,
该Servlet线程阻塞时,前端发送请求会再创建该Servlet的对象
*/