Servlet开发须知知识点

目录

Web项目目录结构

  举例,在Intellij IDEA中如下:


Web项目目录结构


  其中这个Web项目被命名为:servlet,即Web工程的名称,在MyEclipse中,配置好我们自己的Tomcat服务器后,该工程部署时,在webapps目录下就会有一个servlet的Web应用。在Intellij IDEA中,部署工程时,会创建一个artifacts文件夹放置生成后可运行的Web应用,而不是在Tomcat服务器下的webapps目录直接生成。(当然我们可以配置部署时Web应用的输出路径,如下)


配置Tomcat部署时Web应用的输出路径


  servlet项目中src目录为Java程序的开发目录,当然我们对Servlet的编写也是在该目录下,该目录下编写的所有程序在部署时,会自动部署到servlet/WEB-INF/classes目录下。
  servlet项目中的web目录(在MyEclipse中为WebRoot目录)对应于Web应用的根目录,该目录下的所有子目录和子文件在部署时,会原封不动的发布到Web应用目录下。在Intellij IDEA中,部署到Tomcat生成的文件如下:


Intellij IDEA部署Web项目后生成的文件目录结构


  在Web项目根目录下的文件可以被外界直接访问,如这里的 1.html,index.jsp。可以直接访问的原因,下面还需要重点说明。
  WEB-INF目录:Java类、jar包、web应用的配置文件存在该目录下,该目录下的文件外界无法直接访问,由Web服务器负责调用。
  在WEB-INF目录下的web.xml文件是整个Web应用中最重要的配置文件,它必须放在WEB-INF目录中。在开发Web应用时,但凡涉及到对Web应用中的Web资源进行配置的操作,均在web.xml文件中进行设置。如:
  - 将某个Web资源配置为网站首页;
  - 将servlet程序映射到某个url地址上;
  - 将Web应用配置监听器;
  - 将Web应用配置过滤器;
  - ……

Servlet的调用过程

  1. 浏览器请求服务器,连接服务器;
  2. 浏览器发送HTTP请求给服务器;
  3. 服务器接收HTTP请求后,解析浏览器想访问的主机名;
  4. 解析浏览器想访问的Web应用;
  5. 解析浏览器想访问的Web资源(这里指的是想访问哪个Servlet);
  6. 根据访问的Servlet,创建Servlet实例对象(内部根据web.xml文件使用反射技术进行创建;当然这里并不是每次请求都会创建Servlet对象,而是首次创建后,后续请求则使用之前创建过的Servlet对象);
  7. 调用servlet实例对象的init方法完成对象初始化操作;
  8. (服务器)创建代表请求的request和代表响应的response对象,然后调用servlet这个实例对象的service方法;
  9. 执行servlet实例对象的service方法过程中,向代表客户端响应的response对象写入向浏览器输出的数据;
  10. service方法执行完毕后,服务器从response对象中取出数据,并构建出一个HTTP响应,响应客户机;
  11. 浏览器获取到服务器返回的HTTP响应,解析HTTP响应,读取数据进行显示。

Servlet的运行过程

  Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
  Servlet程序是由Web服务器调用的,Web服务器接收到客户端的Servlet访问请求后:
  (当然,客户端请求Servlet后,Web服务器需要根据web.xml配置查找客户端请求的Servlet,即判断客户端是在请求哪个Servlet。)
1. Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第 4 步,否则执行第 2 步。
2. 装载并创建该Servlet的一个实例对象。
3. 调用Servlet实例对象中的init()方法。
4. 对HTTP请求消息进行封装,创建并封装为HttpServletRequest对象和创建一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。(在调用service()方法的过程中,该方法会根据请求的方式调用对应的doXxx方法)
5. Web应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destory()方法。

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

  在Servlet的整个生命周期内,Servlet的init方法只被调用一次(即在Servlet创建时)。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次Servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service方法,service方法再根据请求方式调用对应的doXxx方法。

Servlet接口实现类

  • 对于Servlet接口,SUN公司为其定义了两个默认的实现类,分别为:GenericServlet、HttpServlet。HttpServlet类是指能够处理HTTP请求的servlet,在实际开发中,我们一般创建Servlet继承于HttpServlet类。
  • HttpServlet在实现Servlet接口时(实际上HttpServlet继承于GenericServlet),覆盖了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为POST请求,则调用doPost方法。

Servlet的URL映射

  • 由于客户端是通过URL地址访问Web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上。如:
<servlet>
    <servlet-name>ServletDemo1</servlet-name>
    <servlet-class>com.wm103.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ServletDemo1</servlet-name>
    <url-pattern>/ServletDemo1</url-pattern>
</servlet-mapping>
  • 其中<servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name><servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
  • 一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name><url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。
  • 除了通过配置文件方式配置Servlet的URL映射外,还可以通过注解的形式进行配置,这样做后,无需在web.xml中再进行配置,如下:
package com.wm103;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by DreamBoy on 2017/4/27.
 */
@WebServlet(name="ServletDemo3", urlPatterns={"/ServletDemo3"})
/*@WebServlet(name="ServletDemo3", urlPatterns={"/ServletDemo3"},loadOnStartup=1)*/
public class ServletDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getOutputStream().write("This is ServletDemo3.".getBytes());
    }
}
  • 同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
  • 在Servlet映射到的URL中可以使用*通配符,但是只有两种固定格式:1、*.扩展名;2、以正斜杠(/)开头并以“/*”结尾。如下:
<servlet-mapping>
    <servlet-name>ServletDemo2</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>ServletDemo2</servlet-name>
    <url-pattern>/action/*</url-pattern>
</servlet-mapping>

  即任何以.html结尾的URL都有可能匹配访问到ServletDemo2;任何以/action开头的URL都有可能匹配访问到ServletDemo2。
- 那么根据Servlet配置的URL映射关系,对于某一URL而言,可能符合多个Servlet配置的URL映射关系,这时将选择匹配度最高的Servlet。此外,这里需要强调下,以 *开头的url-pattern设置其优先级最低。
- 要求在Web应用程序启动时,就装载并创建Servlet的实例对象,并调用Servlet实例对象中的init方法,可以在web.xml中的<servlet>元素中配置一个<load-on-start-up>元素,元素的值表示装载并创建Servlet的优先级,其值越小则优先级越高,即越先被创建。

<servlet>
    <servlet-name>ServletDemo1</servlet-name>
    <servlet-class>com.wm103.ServletDemo1</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

  以注解方式的配置则如下:

@WebServlet(name="ServletDemo3", urlPatterns={"/ServletDemo3"},loadOnStartup=1)

重点

  • 如果某个Servlet的映射路径设置为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。(注:经测试设置/*,同样也配置了缺省Servlet)即当URL匹配不到任何一个Servlet时,Web服务器就会调用缺省Servlet。
  • 凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其它Servlet都不处理的访问请求。
  • <tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为缺省Servlet。如下:
<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>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
  • 当访问Tomcat服务器中某个静态HTML文件和图片时,实际上是访问Tomcat服务器默认设置的缺省Servlet,即org.apache.catalina.servlets.DefaultServlet

Servlet线程安全

  • 当多个客户端并发访问同一Servlet时,Web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
  • 如果某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。
  • SingleThreadModel接口中没有定义任何方法,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。(没有定义任何东西的接口,也称为标记接口,如:Serializable、Cloneable接口)
  • 对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象。
  • 实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。
  • 事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过时的)。建议开发人员应当采取其他手段来解决这些问题,而不是实现该接口,比如 避免实例变量的使用或者在访问资源时同步代码块(即synchronized中)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值