浅谈Servlet

习惯了在各类 Web 框架上进行开发,和而 Servlet的关系就是,每天都在接触,又不是很熟。 今天就来扒一扒servlet的相关内容。

在之前的一篇讲JSP的文章中,有提到过jsp的本质就是Servlet 。

而Servlet(全称为 Server Applet),是在服务器上运行的Java程序,本质上是一段java程序,没有main方法,不能独立运行,必须把它部署到 Servlet 容器中,由容器来实例化并调用 Servlet,是由SUN公司提供的动态web资源开发技术。

Servlet 的作用是处理请求,服务器接受到的请求,找到对应的Servlet处理,Servlet接受请求、处理请求、将结果响应给浏览器。

1.如何管理Servlet

我们知道Servlet是处理请求,从http请求的Request中获取参数信息,并将响应结果返回到Response当中,承担了具体的业务功能的实现。

业务功能千千万,需要统一接口形式才好管理,称为Servlet 接口。实现了这个接口的业务类,就可以称为Servlet。

面对众多的Servlet,为了方便实例化和调用,引入了Servlet 容器,用来加载和管理业务类。

**如此一来:**HTTP 服务器把请求交给 Servlet 容器,Servlet 容器将请求转发到具体的 Servlet,如果这个 Servlet 还没创建,就加载并实例化这个 Servlet,然后调用这个 Servlet 的接口方法。

2.Servlet 接口

在Servlet接口中定义了五个方法:

public interface Servlet {
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}
  1. init 和 destroy是两个生命周期有关的方法,容器在加载 Servlet 类的时候会调用 init 方法,在卸载的时候会调用 destroy 方法。可以在 init 方法里初始化一些资源,并在 destroy 方法里释放这些资源。
  2. ServletConfig类封装了 Servlet 的初始化参数。可以在web.xml给 Servlet 配置参数,并在程序里通过 getServletConfig 方法拿到这些参数。
  3. service 方法,实现具体的业务处理逻辑。这个方法有两个参数:ServletRequest (封装请求信息)和 ServletResponse(封装响应信息)

这里有两个常见的继承类, GenericServletHttpServlet

GenericServlet是一个抽象类,实现了 Servlet 接口,并且对其中的 init() 和 destroy() 和 service() 提供了默认实现。

HttpServlet 也是一个抽象类,它进一步继承并封装了 GenericServlet,使得使用更加简单方便,由于是扩展了 Http 的内容,所以还需要使用 HttpServletRequest 和 HttpServletResponse,这两个类分别是 ServletRequest 和 ServletResponse 的子类。

常用的创建方法是继承 HttpServlet 方法 ,重写doGet()和doPost()请求。

public class ServletDemo extends HttpServlet {

    @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");
        doGet(req,resp);
    }
}

3.Servlet 容器

3.1处理过程

在了解Servlet 容器前,首先看一下http请求的处理流程:

在这里插入图片描述

①HTTP 服务器把客户的请求信息封装成 ServletRequest 对象,然后调用 Servlet 容器的 service 方法;

②Servlet 容器拿到请求后,根据请求的 URL 和 Servlet 的映射关系,找到相应的 Servlet;

③如果 Servlet 还没有被加载,就用反射机制创建这个 Servlet,并调用 Servlet 的 init 方法来完成初始化;

④接着调用 Servlet 的 service 方法来处理请求;

⑤把响应结果封装成 ServletResponse 对象,返回给 HTTP 服务器,HTTP 服务器会把响应发送给客户端。

3.2 注册Servlet

不知道大家有没有注意到,java后端项目的,项目结构都大同小异。基本都满足下面的结构。

| -  WebApp
      | -  WEB-INF/web.xml        -- 配置文件,用来配置Servlet等
      | -  WEB-INF/lib/           -- 存放Web应用所需各种JAR包
      | -  WEB-INF/classes/       -- 存放应用类,比如Servlet类
      | -  META-INF/              -- 存放工程的一些信息

这其实也契合了Servlet 规范,Web 应用程序有一定的目录结构,Servlet 容器通过读取配置文件,就能找到并加载 Servlet。

Servlet 规范里定义了 ServletContext 这个接口来对应一个 Web 应用。

Web 应用部署好后,Servlet 容器在启动时会加载 Web 应用,并为每个 Web 应用创建唯一的 ServletContext 对象。

ServletContext 可以看作是一个全局对象,一个 Web 应用可能有多个 Servlet,这些 Servlet 可以通过全局的 ServletContext 来共享数据,这些数据包括 Web 应用的初始化参数、Web 应用目录下的文件资源等。

由于 ServletContext 持有所有 Servlet 实例,还可以通过它来实现 Servlet 请求的转发。

3.3 扩展

通过servlet接口,和servlet容器的统一管理,对于开发人员来说,只需要实现servlet的业务逻辑,不用操心网络通信,servlet的实例化等。

此外,Servlet 规范提供了两种扩展机制:Filter 和 Listener。

1.Filter 过滤器:这个接口允许对请求和响应做一些统一的定制化处理;

过滤器的工作原理是这样的:Web 应用部署完成后,Servlet 容器需要实例化 Filter 并把 Filter 链接成一个 FilterChain。当请求进来时,获取第一个 Filter 并调用 doFilter 方法,doFilter 方法负责调用这个 FilterChain 中的下一个 Filter。

2.Listener 监听器:当 Web 应用在 Servlet 容器中运行时,Servlet 容器内部会不断的发生各种事件。 通过监听器,可以监听一些时间,进行对应的操作。Servlet 容器提供了一些默认的监听器来监听这些事件,此外,也可以自定义自己的监听器去监听你感兴趣的事件,将监听器配置在web.xml中。

4.servlet容器与spring容器

类似于 Tomcat 和 Jetty之类的web容器,本质上是 Servlet 容器的具体实现,都符合servlet的上述规范。

通过上述内容,我们知道Servlet 容器在启动时会加载 Web 应用,并为每个 Web 应用创建唯一的 ServletContext 对象。这个全局的上下文对象,为后面的Spring容器提供宿主环境。

同时,Servlet 容器在启动过程中触发容器初始化事件,Spring的ContextLoaderListener会监听到这个事件,它的contextInitialized方法会被调用,在这个方法中,Spring会初始化全局的Spring根容器,这个就是Spring的IoC容器,IoC容器初始化完毕后,Spring将其存储到ServletContext中,便于以后来获取。

Servlet 容器在启动过程中还会扫描Servlet,一个Web应用中的Servlet可以有多个,以SpringMVC中的DispatcherServlet为例(DispatcherServlet是一个标准的前端控制器,用以转发、匹配、处理每个Servlet请求)。

Servlet一般会延迟加载,当第一个请求达到时,Servlet 容器发现DispatcherServlet还没有被实例化,就调用DispatcherServlet的init方法,DispatcherServlet在初始化的时候会建立自己的容器,叫做SpringMVC 容器,用来持有Spring MVC相关的Bean。同时,Spring MVC还会通过ServletContext拿到Spring根容器,并将Spring根容器设为SpringMVC容器的父容器。(Spring MVC容器可以访问父容器中的Bean,但是父容器不能访问子容器的Bean)。

所以,我们一般在配置文件中,划清楚Spring MVC容器和Spring容器的功能。

  1. Spring根容器负责所有其他非controller的Bean的注册

  2. SpringMVC只负责controller相关的Bean的注册,其中@ControllerAdvice用于对控制器进行增强,常用于实现全局的异常处理类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值