Servlet从初识到熟悉

Servlet基本认识

Servlet的本质就是一个接口,有的人往往以为就是Servlet直接处理客户端的http请求,其实并不是这样,servlet并不会去监听端口;直接与客户端打交道是我们前面已经学过的Tomcat服务器。
客户端发送请求到tomcat,它监听端口,请求到达tomcat,根据url等信息,确定要将请求交给哪个servlet去处理,然后调用那个servlet的service方法,service方法返回一个response对象,tomcat再把这个response返回给客户端。如下图就是整个执行过程。
servlet_demo1 : 是一个moudle即一个项目
ServletDemo01 : 是一个servlet
在这里插入图片描述

Servlet生命周期

  1. 调用 init() 方法初始化
  2. 调用 service() 方法来处理客户端的请求
  3. 调用 destroy() 方法释放资源,标记自身为可回收
  4. 被垃圾回收器回收
package com.wunan.servlet;

import javax.servlet.*;
import java.io.IOException;

public class StudentServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * 所有的客户端请求都会经过这个service方法
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("这是一个servlet入门工具类");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

Servlet继承关系

  • 第一种:
    • 实现Servlet接口,实现所有的抽象方法,该方法支持最大程度的自定义。
  • 第二种:
    • 继承GenericServlet抽象类,必须重写service方法,其他方法可以选择重写,该方式可以让开发Servlet变得简单,但是和Http协议没有关系,比如不能指定请求方法。
  • 第三种:
    • 继承HttpServlet抽象类,需要重写doGet和doPost方法,这也是最常用的方法。
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

快速入门

首先创建一个java web项目,配置好tomcat,配置前需要检查tomcat的lib目录下是否有servlet的jar,并且检查jar不为空(有一次下载的tomcat jar里的javax类空,导致无法实现servlet接口)。

  1. 在src下新建一个类叫ServletDemo,然后继承HttpServlet。
package com.wunan.servlet;

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

public class ServletDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("方法执行了。。。");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

  1. 然后在web.xml中声明Servlet,其中servlet中的name与servlet-mapping中的name要保持一致,url即访问时要输入的地址。
    <servlet>
        <servlet-name>servletDemo01</servlet-name>
        <servlet-class>com.wunan.servlet.ServletDemo01</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>servletDemo01</servlet-name>
        <url-pattern>/servletDemo01</url-pattern>
    </servlet-mapping>
  1. 检查tomcat的war包。
    在这里插入图片描述
  2. 打开浏览器访问,就可以在控制台中看见输出的语句 。(http://localhost:8080/Servlet_demo3_war_exploded/servletDemo01)

注意:当有多个浏览器的请求同时打到同一个Servlet时,容器会起多个线程同时访问一个servlet的service()方法,有可能会出现线程安全的问题,因此能使用局部变量尽量使用局部变量,否则需要对成员变量进行加锁处理。

面试问题:Servlet如何同时处理多个请求访问?

单实例多线程: 主要是请求来时,会由线程调度者从线程池李取出来一个线程,来作为响应线程。这个线程可能是已经实例化的,也可能是新创建的。

Servlet容器默认是采用单实例多线程的方式处理多个请求的:
1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在一个Servlet实例);
2.容器初始化化Servlet主要就是读取配置文件(例如tomcat,可以通过servlet.xml的设置线程池中线程数目,初始化线程池通过web.xml,初始化每个参数值等等。
3.当请求到达时,Servlet容器通过调度线程(Dispatchaer Thread) 调度它管理下线程池中等待执行的线程(Worker Thread)给请求者;
4.线程执行Servlet的service方法;
5.请求结束,放回线程池,等待被调用;
(注意:避免使用实例变量(成员变量),因为如果存在成员变量,可能发生多线程同时访问该资源时,都来操作它,照成数据的不一致,因此产生线程安全问题)

从上面可以看出:
第一:Servlet单实例,减少了产生servlet的开销;
第二:通过线程池来响应多个请求,提高了请求的响应时间;
第三:Servlet容器并不关心到达的Servlet请求访问的是否是同一个Servlet还是另一个Servlet,直接分配给它一个新的线程;如果是同一个Servlet的多个请求,那么Servlet的service方法将在多线程中并发的执行;
第四:每一个请求由ServletRequest对象来接受请求,由ServletResponse对象来响应该请求;

Servlet的不同映射方式

<!--    Servlet不同的映射方式-->
<!--    指定名称的方式-->
<!--    <servlet>-->
<!--        <servlet-name>servletDemo05</servlet-name>-->
<!--        <servlet-class>com.wunan.servlet.ServletDemo05</servlet-class>-->
<!--    </servlet>-->

<!--    <servlet-mapping>-->
<!--        <servlet-name>servletDemo05</servlet-name>-->
<!--        <url-pattern>/servletDemo05</url-pattern>-->
<!--    </servlet-mapping>-->

<!--        <servlet>-->
<!--            <servlet-name>servletDemo05</servlet-name>-->
<!--            <servlet-class>com.wunan.servlet.ServletDemo05</servlet-class>-->
<!--        </servlet>-->

<!--        不管servlet后面写什么都能匹配到-->
<!--        <servlet-mapping>-->
<!--            <servlet-name>servletDemo05</servlet-name>-->
<!--            <url-pattern>/servlet/*</url-pattern>-->
<!--        </servlet-mapping>-->

<!--        匹配到 .hahah 结尾的地址,注意*号前面没有 / -->
<!--            <servlet-mapping>-->
<!--                <servlet-name>servletDemo05</servlet-name>-->
<!--                <url-pattern>*.hahah</url-pattern>-->
<!--            </servlet-mapping>-->

Servlet注解开发

在JavaWeb开发中, 每次编写一个Servlet都需要在web.xml文件中进行配置,如下所示:

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.wunan.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
</servlet-mapping>

每开发一个Servlet,都要在web.xml中配置Servlet才能够使用,这实在是很头疼的事情,所以Servlet3.0之后提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署描述,简化开发流程。

Servlet基于注解的配置方式

在直接在servlet类名上面写以下注解,能达到同样的效果:

@WebServlet("/login")
package com.sponge.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值