JavaEE核心API--Servlet

来源:互联网 发布:淘宝网借贷 编辑:程序博客网 时间:2024/05/18 21:40

一.Servlet简介

Servlet是serverapplet的简写,意为服务器端程序。用来处理客户端浏览器发来的请求,并相应给浏览器动态资源
Servlet是JavaWeb三大组件(Servlet,Filter,Listener)

1.1 Servlet的功能

Servlet用来处理动态资源,其根本任务是,处理请求,生成响应。

1.2 Servlet的工作方式

Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎(即服务器,如:Tomcat)来控制和调度。

1.3 Servlet的生命周期

如果客户端的多次发出Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,Servlet实例对象才会销毁。

这里写图片描述

Servlet的生命周期方法的执行:

1)第一次调用Servlet时,将执行初始化方法,init(ServletConfig),创建Serlvet的实例,以单实例的形式创建(Struts2的动作类则是多实例的)。
2)每一次调用都执行service(ServletResquest , ServletResponse)方法。
3)服务器关闭(或项目移除),调用destroy( )方法销毁Servlet的实例。

二.Servlet的基本使用

2.1 Servlet的创建

方式一:实现servlet接口.
方式二:继承javax.servlet.GenericServlet
方式三:继承javax.servlet.http.HttpServlet

2.2 Servlet的生命周期方法

生命周期方法指的是调用之后必须要执行的方法。对于servlet来讲,有3个生命周期方法。

声明周期 方法 功能 出生 init() 在构造方法调用之后调用 使命 service() 当请求发来时,处理请求使用 销毁 destory() 当服务器关闭时,会销毁servlet,在销毁之前调用该方法释放资源

2.3 Servlet中的其他方法

Servlet对象一共有5个方法,除了3个和生命周期有关的方法外,还有2个不常用的方法:

getServletInfo()方法,获得servlet的信息(版本,作者,版权..),基本不用

getServletConfig()方法,返回servletConfig对象

2.4 Servlet技术中各对象的作用范围

对象 作用范围 servlet 项目启动期间一个servlet只有一个servlet实例 request 项目启动期间,request对象的数量,要看当前有多少个请求正在处理 response 项目启动期间,reponse对象的数量,要看当前有多少个请求正在处理 servletConfig 一个servlet实例对应一个servletConfig对象 servletContext 整个项目中只有一个servletContext实例

三.ServletConfig接口

功能:封装了servlet在web.xml中的配置,ServletConfig的API:
1.getServletName 获得配置文件中< servlet-name >元素的内容
2.getInitParameter 根据< init-param >中的 < param-name > 获得 < /param-value >

<init-param>    <param-name>name</param-name>    <param-value>tom</param-value></init-param>

getInitParameterNames返回所有< param-name >
getServletContext返回ServletContext对象

四.ServletContext接口

服务器启动的时候会为每一个WEB应用创建一个单独的ServletContext对象,ServletContext对象中的数据可以在整个WEB应用中获取(需要使用ServletContext对象的获取值的方法)

4.1 ServletContext封装了web.xml中的配置

<context-param>     <param-name>name</param-name>     <param-value>jerry</param-value></context-param><context-param>     <param-name>password</param-name>      <param-value>1234</param-value></context-param>

可以使用ServletContext中的方法获得web.xml中的配置内容:
getInitParameterNames(); 获得所有键
getInitParameter(key); 根据键获得对应的值

4.2 Servlet技术中三大域对象(application域,session域,request域)之一

“域”即存储数据的区域,Request,Session和ServletContext对象都有存取数据的功能,所以又被称为“域”。ServletContext对应着application域。application域中的数据可以再整个项目范围内存取。(注:JSP中为四大域,多了一个页面域—-page域

关于域的操作:

操作 对应方法 放入键值对 setAttribute(key,value) 通过键取值 getAttribute(key) 通过键删除 removeAttribute(key) 遍历所有键 getAttributeNames()

ServletContext的常用功能:

ServletContext中的数据可以在整个项目中存取,所以可以用来做Servlet对象之间的通信

这里写图片描述

4.3 获得项目中资源

所有servletContext中关于路径的获得,相对路径都是相对的 WebRoot(项目根)下
getRealPath 通过相对路径获得绝对路径
getResourceAsStream 根据相对路径获得指定资源流

五.实现了Servlet接口的类

在Servlet的API中有2个实现了Servlet接口的类,对Servlet进行了封装和优化,方便开发人员的使用

5.1 GenericServlet

实现了ServletConfig接口,方便调用(在init方法中做的优化)

GenericServlet有两个init方法,使用时调用空参的init方法,含参的init方法做了优化

public void init(ServletConfig config) throws ServletException {        this.config = config;        this.init();    }
public void init() throws ServletException {    }

GenericServlet源码

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {    private static final long serialVersionUID = 1L;    private transient ServletConfig config;    public GenericServlet() {    }    public void destroy() {    }    public String getInitParameter(String name) {        return this.getServletConfig().getInitParameter(name);    }    public ServletConfig getServletConfig() {        return this.config;    }    public ServletContext getServletContext() {        return this.getServletConfig().getServletContext();    }    public void init(ServletConfig config) throws ServletException {        this.config = config;        this.init();    }    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;    .......}

5.2 HTTPServlet

1.HTTPServlet是在GenericServelt的基础上做的进一步的优化,是一个抽象类。

2.因为我们WEB项目都是基于HTTP协议,所以Service方法中的request,response对象都是基于HTTP协议的。也就是HttpServletReueqst和HttpServletResponse。它帮我们进行了强转.

3.根据不同的请求采取不同的方法进行处理。有专门处理GET和POST请求的方法。

HTTPServlet部分源码

public abstract class HttpServlet extends GenericServlet {    private static final long serialVersionUID = 1L;    private static final String METHOD_GET = "GET";    private static final String METHOD_POST = "POST";    private static final String METHOD_PUT = "PUT";    private static final String HEADER_IFMODSINCE = "If-Modified-Since";    private static final String HEADER_LASTMOD = "Last-Modified";    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");    public HttpServlet() {    }    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        String protocol = req.getProtocol();        String msg = lStrings.getString("http.method_get_not_supported");        if (protocol.endsWith("1.1")) {            resp.sendError(405, msg);        } else {            resp.sendError(400, msg);        }    }    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        String protocol = req.getProtocol();        String msg = lStrings.getString("http.method_post_not_supported");        if (protocol.endsWith("1.1")) {            resp.sendError(405, msg);        } else {            resp.sendError(400, msg);        }    }

六.Servlet线程安全问题

因为在servlet运行期间只有一个servlet实例存在.可能会同时处理多个请求.那么我们在servlet中声明成员变量来存储用户数据是有线程安全问题的.
解决方法:

6.1 实现SigleThreadModel (不推荐)

SigleThreadModel本质上是一个标记接口,类似Serializable,标记接口的主要作用就是给某个对象打上一个标志,告诉JVM,这个对象可以做什么,比如实现了”Serializable”接口的类的对象就可以被序列化,而实现” SigleThreadModel ” 接口的类的对象则可以创建多个实例,所以这种方法解决线程安全的原理是创建多个Servlet实例,每个线程分配一个Servlet的实例对象,会使占用很多内存,所以这种解决办法不好,很少用

6.2 使用局部变量保存用户数据(推荐)

若service()方法里有一个局部变量n,当有多个线程并发访问service()方法时,Servlet不会创建新的实例,而是每次访问都调用一次service()方法,所以每一个线程里面都有自己的n变量,各个线程操作的都是自己的n变量,所以不存在线程安全问题。
多线程并发访问某一个方法的时候,如果在方法内部定义了一些资源(变量,集合等),那么每一个线程都有这些东西,所以就不存在线程安全问题了。

七.Servlet随着服务器的启动而创建

Servlet实例默认是在第一次访问时创建,在web.xml文件中可以设置更改Servlet实例的创建时机,改为服务器启动后直接创建Servlet的实例
使用< load-on-startup >配置来实现.
例如:

<servlet>      <servlet-name>AServlet</servlet-name>      <servlet-class>cn.itcast.servlet.hello.AServlet</servlet-class>      <load-on-startup>3</load-on-startup></servlet>

< load-on-startup >标签内填写一个整数,每个Servlet都可以独立设置一个启动常数,这个常数数值越小代表优先级越高,创建时优先创建。如果优先级一样,启动顺序按照配置顺序。

八.关于Servlet路径配置问题详解

web.xml文件中的< url-pattern > 标签配置目标资源路径

完全路径匹配:

特点:路径完整,指定Servlet对象

XML中的配置 访问时使用路径 /AServlet http://localhost:8080/Day07-servlet/AServlet /ABC/AServlet http://localhost:8080/Day07-servlet/ABC/AServlet

目录匹配:

特点:以 * 结束,代表匹配一定范围内的资源

XML中的配置 访问时使用路径 /ABC/ABC/* http://localhost:8080/Day07-servlet/ABC/ABC/ServletName /* http://localhost:8080/Day07-servlet/ServletName / /* (即可以是项目下的任意资源)

后缀名匹配:

特点:匹配后缀名

后缀名 使用环境 *.do struts *.action struts2 *.html 自定义匹配(很少用)

注意:

1.关于路径,配置的路径匹配范围越大优先级越低
优先级排序:完全路径匹配>目录匹配>后缀名匹配

2.两种匹配模式不能混用.例如错误的例子: /*.do

缺省Servlet

缺省Servlet的映射路径为“/”,若一个请求在web.xml文件中匹配不到Servlet,那么这个请求就会交给缺省Servlet处理

在Tomcat默认的配置文件/conf/web.xml中就配置有缺省Servlet
当访问Tomcat服务器中的静态文件时,底层就是调用这个默认的缺省Servelt进行处理的

<servlet>        <servlet-name>default</servlet-name>        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>        <init-param>            <param-name>debug</param-name>            <param-value>0</param-value>        </init-param>        <init-param>            <param-name>listings</param-name>            <param-value>false</param-value>        </init-param>        <load-on-startup>1</load-on-startup></servlet>
原创粉丝点击