Servlet以及单例设计模式
1.Servlet概述
a)Servlet,全城是Servlet Applet,服务器端小程序,是一个接口,定义了若干方法,要求所有的Servlet必须实现。
b)Servlet用于接收客户端的请求,并对请求做出相应的相应。
c)Servlet中的方法:
>init:用于初始化Servlet;
>service:用于(执行)服务;
>destroy:在Servlet被销毁前调用;
d)Servlet是一个接口,为了方便使用,官方提供了对应的实现类,关系如下:
Servlet: -- GenericServlet(c):通用协议的Servlet;
--HttpServlet(c):专门用于HTTP的Servlet;
2.定义Servlet并配置
2.1定义Servlet
测试时继承了GenericServlet,实际使用时建议使用HttpServlet.
package com.bjsxt.servlet;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class FirstServlet extends GenericServlet{
public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException{
System.out.println("FirstServlet.service()");
//响应信息
res.getWriter().print("<h1>Hello Servlet!</h1>");
}
}
2.2配置Servlet
在web.xml中配置Servlet,告诉Tomcat在客户端访问哪个路径时,应该执行哪个Servlet.
<!-- 配置Servlet -->
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>com.bjsxt.servlet.FirstServlet</servlet-class>
</servlet>
<!-- 配置Servlet映射 -->
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/abc</url-pattern>
<!-- http://localhost:8080/0529_servlet_hello/abc -->
</servlet-mapping>
3.Servlet的执行过程(图略)
a)客户端通过浏览器输入URL地址访问Tomcat
b)Tomcat解析URL路径
c)到当前项目的web.xml中匹配Servlet的映射路径;
---如果匹配成功,则调用对应的Servlet的service方法;
---如果没有匹配成功,则继续到Tomcat的web.xml中匹配。
d)在Tomcat的web.xml中,提供了两个Servlet,分别为DefaultServlet和JspServlet.
---JspServlet用于处理jsp
---DefaultServlet处理没有匹配到其他Servlet的所有请求,用于加载静态资源或404异常。
4.Servlet配置详解
a)web.xml的名称不能改变,位置不能改变;
b)<servlet-name>和<servlet-class>要写正确,必须要匹配;
c)关于<url-pattern>的几种配置方式:
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<!-- 固定路径, 必须以/开头 -->
<url-pattern>/abc</url-pattern>
<!-- 以xxx结尾的路径 -->
<url-pattern>*.sxt</url-pattern>
<!-- 访问xxx下的路径 -->
<url-pattern>/sxt/*</url-pattern>
<!-- 不可以使用如下的方式 -->
<!-- <url-pattern>/sxt/*.aaa</url-pattern> -->
<!-- 匹配所有的路径, 包括jsp -->
<url-pattern>/*</url-pattern>
<!-- 匹配所有除了jsp之外的路径 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
5.解决405异常
a)在HttpServlet中,service方法用于分发请求,例如:如果是get方式,就调用doGet方法;如果是post方式,就调用doPost方法。
b)而HttpServlet中的doPost方法和doGet方法没有做什么事,就发送了一个405异常,因此,一旦执行到这两个方法就会报405异常。
c)解决405异常的两种方式:
---子类重写service方法:
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("DemoServlet.service()");
}
}
---子类重写doGet和doPost方法:
public class DemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("DemoServlet.doGet()");
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("DemoServlet.doPost()");
}
}
6.单例设计模式
a)设计模式是解决特定问题的最佳方案。
b)单例,单个对象,在对象的使用过程中,永远都只创建一个对象;
c)饿汉式单例,类加载时就创建对象,由于静态成员变量只被加载一次,所以保证了对象之创建一次;
package com.bjsxt.singleton;
/**
* 饿汉式单例
* 不管这个对象是否被使用, 先被创建
* @author Administrator
*
*/
public class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("创建对象[饿汉式]");
}
/**
* 静态方法, 用于给其他类提供对象
*
* @return
*/
public static HungrySingleton getInstance() {
return instance;
}
}
d)懒汉式单例,在需要的时候才创建对象,多线程时不安全,需要使用双重检查机制保证线程安全;
package com.bjsxt.singleton;
/**
* 懒汉式单例
*
* @author Administrator
*
*/
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("创建对象[懒汉式]");
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
// Double Check, 双重检查
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
7.饿汉式单例和懒汉式单例的比较
a)饿汉式:
>代码非常简单。
>类加载时及创建对象,该对象可能并不会被使用。
>多线程下也可以保证单例的实现,没有问题。
>省去了判断,效率较高;
b)懒汉式:
>代码较为复杂
>类加载时不会创建对象,需要时才创建,不会创建多余的对象。
>多线程时可能会有线程安全问题,需要进行Double Check。
>需要很多判断,效率较低;
8.Servlet的生命周期
a)Servlet是单实例,多线程的
b)生命周期阶段:
----创建:构造器,只创建一次;
----初始化:innit,只初始化一次;
---执行:service,累一次请求执行一次;
---销毁:destroy,项目卸载或服务关闭时,Servlet被销毁,销毁前会由服务器调用destriy方法;
c)默认情况下,Servlet是懒汉式单例,对象是在第一次请求时被创建的。
d) 如果希望Servlet在服务器启动时就创建, 可以在<servlet>标签下通过<load-on-startup>标签进行指定. 该标签需要配置一个整数:
- 负整数: 和不配置一样, 表示第一次请求时创建和初始化.
- 0和正整数: 表示服务器启动时就创建和初始化, 数字越小, 被加载的优先级越高. 如果数字相同, 加载顺序由服务器决定.