Servlet的生命周期

1.servlet是什么

2.servlet生命周期

3. servlet 工作原理

4 .ServletContextListener全局监听器

什么是Servlet?

Servlet是JavaWeb的 三大组件之一 ,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:

  • 接收请求数据;  客户端发送请求至服务器

  • 处理请求; 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器

  • 完成响应。 服务器将响应返回客户端

  例如客户端发出登录请求,或者输出注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写,每个Servlet必须实现javax.servlet.Servlet接口。

Web 服务器接收 HTTP 请求。

Web 服务器将请求转发到 Servlet 容器。

如果对应的 Servlet 不在容器中,那么将被动态检索并加载到容器的地址空间中。

容器调用 init() 方法进行初始化(仅在第一次加载 Servlet 时调用一次)。

容器调用 Servlet 的 service() 方法来处理 HTTP 请求,即读取请求中的数据并构建响应。

Servlet 将暂时保留在容器的地址空间中,可以继续处理其它 HTTP 请求。

Web 服务器将动态生成的结果返回到浏览器/客户端。

 

实现Servlet有三种方式:

  • 实现javax.servlet.Servlet接口;

  • 继承javax.servlet.GenericServlet类;

  • 继承javax.servlet.http.HttpServlet类; 

GenericServlet是Servlet接口的实现类。

HttpServlet类是GenericServlet的子类,它提供了对HTTP请求的特殊支持。

Servlet中的方法由Tomcat来调用。并且Servlet的对象也不由我们来创建,由Tomcat来创建!

在web.xml中配置Servlet的目的是把访问路径与一个Servlet绑定到一起

再使用springmvc创建项目时servlet-class 为 

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

或者使用注解 ` @RequestMapping`

<servlet>		
    <servlet-name>hello</servlet-name>		
    <servlet-class>org.csmf.servlet.HelloServlet</servlet-class>	
</servlet>	
<!-- <servlet>`和`<servlet-mapping>`通过`<servlet-name>`这个元素关联在一起了!-->
<servlet-mapping>		
    <servlet-name>hello</servlet-name>		
    <url-pattern>/helloworld</url-pattern>	
</servlet-mapping> 

Servlet的生命周期

Servlet的生命周期可以分为初始化阶段,运行阶段和销毁阶段三个阶段

public interface Servlet { 
    //初始化
    public void  init(ServletConfig config)  throws  ServletException; 
    public ServletConfig getServletConfig();  //返回由Servlet容器传给init( )方法的ServletConfig对象。
    // 运行
    public void  service(ServletRequest req, ServletResponse res) throws      ServletException, IOException;      
    public  String getServletInfo();  //返回Servlet的一段描述,可以返回一段字符串。  
    //销毁   
    public  void   destroy();
}

Servlet的生命周期一般可以用三个方法来表示:

  1. init():仅执行一次,负责在装载Servlet时初始化Servlet对象
  2. service() :核心方法,一般HttpServlet中会有get,post两种处理方式。在调用doGet和doPost方法时会构造servletRequest和servletResponse请求和响应对象作为参数。
  3. destory():在停止并且卸载Servlet时执行,负责释放资源

Servlet的出生

服务器会在Servlet 第一次被访问时创建

一个Servlet类型,服务器只创建一个实例对象

首次访问servlet时,先查看是否已经创建过,如果没有,服务器才会通过反射来创建实例。再次访问时,就直接使用上次创建的实例。

在Servlet被创建后,服务器会马上调用Servlet的void init(ServletConfig)方法。

  • ServletConfig 配置对象

        它对应Servlet的配置信息,对应web.xml文件中的<servlet>元素。

        String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;

        Enumeration getInitParameterNames(String name):用来获取在web.xml中配置的所有初始化参数名称

ServletConfig对象 servlet配置对象

ServletContext对象  servlet的上下文对象

   ServletContext getServletContext(); 获得ServletContext对象

  • ServletContext  

         ServletContext对象表示Servlet应用程序。每个Web应用程序都只有一个ServletContext对象。

ServletContext翻译成中文叫做“Servlet上下文”或者“Servlet全局”,但是这个翻译我认为翻译的实在是有点牵强,也导致了许多的开发者不明白这个变量到底具体代表了什么。其实ServletContext就是一个“域对象”,它存在于整个应用中,并在在整个应用中有且仅有1份,它表示了当前整个应用的“状态”,你也可以理解为某个时刻的ServletContext代表了这个应用在某个时刻的“一张快照”,这张“快照”里面包含了有关应用的许多信息,应用的所有组件都可以从ServletContext获取当前应用的状态信息。ServletContext随着程序的启动而创建,随着程序的停止而销毁。通俗点说,我们可以往这个ServletContext域对象中“存东西”,然后也可以在别的地方中“取出来”。
 

      

因为有了ServletContext对象,就可以共享从应用程序中的所有资料处访问到的信息,并且可以动态注册Web对象。前者将对象保存在ServletContext中的一个内部Map中保存在ServletContext中的对象被称作属性。

ServletContext中的下列方法负责处理属性:

Object getAttribute(String var1);   是获取对象容器中的数据值;
Enumeration<String> getAttributeNames();
void setAttribute(String var1, Object var2);
void removeAttribute(String var1);

Servlet服务

 当服务器每次接收到请求时,都会去调用Servlet的service(ServletRequest req, ServletResponse res)方法来处理请求。

   Servlet容器对于接受到的每一个Http请求,都会创建一个ServletRequest对象和一个ServletResponse对象,并把这两个对象传递给Servlet的Sevice( )方法

  • ServletRequest 请求对象

         它封装了所有与请求相关的数据

        

        String getParameter(String var1);//返回请求参数的值

  • ServletResponse 响应对象

        在service()方法中完成对客户端的响应需要使用这个对象

ServletRequest和ServletResponse的实例由服务器创建,然后传递给service()方法。

Servlet的销毁

在服务器被关闭时,先去调用Servlet的destroy()方法 ,再去销毁Servlet

以下过程属于初始化阶段是 A C D

A.加载Servlet类及.class对应的数据
B.创建servletRequest和servletResponse对象  运行阶段
C.创建ServletConfig对象 
D.创建Servlet对象

初始化阶段:Servlet启动,会读取配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,将ServletConfig作为参数来调用init()方法。所以选ACD。B是在调用service方法时才构造的

如何获取ServletContext设置的参数值? B

A.context.getParameter() 是获取POST/GET传递的参数值;
B.context.getInitParameter() 获取Tomcat的server.xml中设置Context的初始化参数
C.context.getAttribute()  是获取对象容器中的数据值;
D.context.getRequestDispatcher() 请求转发。
通过ServletConfig接口的getInitParameter(java.lang.String name)方法可以获得Servlet的初始化参数

session存放在哪里?

cookie存放在哪里?

HttpServlet

springmvc中web.xml的监听器给干嘛用?

web.xml

  <!--配置一个监听器-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

ContextLoaderListener 继承ContextLoader 实现 ServletContextListener 

这个类也实现了 监听ServletContext初始化和销毁 的两个方法 

ServletContextListener(Servlet全局监听器)

监听ServletContext初始化和销毁  ServletContextListener两个方法

 spring给我们提供的这个监听器类是如何实现的?

当ServletContext初始化后,Spring IOC容器也能跟着初始化的呢?

ApplicationContext是spring的核心 应用的容器 Spring上下文 spring容器负责管理Bean与Bean之间的依赖关系。

webApplicationContext继承自ApplicationContext 该接口提供了 获取 ServletContext 对象的方法

//WebApplicationContext接口
@Nullable
ServletContext getServletContext();

为 web 应用 提供 配置(获取 ServletContext)的接口

ServletContext 同一个web应用的所有Servlet对象共享一个 ServletContext,Servlet对象可以通过它来访问容器中的各种资源 存取共享数据方法: WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。

spring的启动过程:

首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;

其次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取;

 public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
     // 先判断当前servlet 中是否存ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE根容器标识
        if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
            //抛异常  因为已经存在根应用程序上下文
            throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!");
        } else {
            servletContext.log("Initializing Spring root WebApplicationContext");
            Log logger = LogFactory.getLog(ContextLoader.class);
            if (logger.isInfoEnabled()) {
                logger.info("Root WebApplicationContext: initialization started");
            }
            用来计算初始化这个过程会耗费多少时间
            long startTime = System.currentTimeMillis();
​
        try {
                // 1.默认会实例化一个根容器
            if (this.context == null) {
                // spring 会生成一个父级ioc容器 XmlWebApplicationContext
                this.context = this.createWebApplicationContext(servletContext);
            }
XmlWebApplicationContext是ConfigurableWebApplicationContext的实现类,指定的contextClass应该是ConfigurableWebApplicationContext的实现类
​
            if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        //2.为创建的root 容器设置父上下文 一般父上下文为空
                        ApplicationContext parent = this.loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }
                    //3.配置容器并刷新
                    this.configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }
​
​
            //  注册标识 全局共享 将其存储到ServletContext中,避免再被初始化
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
            
            //保存到当前线程
            ClassLoader ccl = Thread.currentThread().getContextClassLoader();
            if (ccl == ContextLoader.class.getClassLoader()) {
                currentContext = this.context;
            } else if (ccl != null) {
                currentContextPerThread.put(ccl, this.context);
            }
​
            if (logger.isInfoEnabled()) {
                long elapsedTime = System.currentTimeMillis() - startTime;
                logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
            }
​
            return this.context;
        } catch (Error | RuntimeException var8) {
            logger.error("Context initialization failed", var8);
             //即使初始化失败仍不允许有再次的初始化        
           
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
            throw var8;
        }
    }
}

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
   //获取context的类
    //在determineContextClass()方法中 经过两个判断来返回context 类的类信息
    Class<?> contextClass = this.determineContextClass(sc);
    //判断是否是ConfigurableWebApplicationContext 的子类
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
        throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
    } else {
        // 生成WebApplicationContext 的对象
        return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
    }
}

ConfigurableApplicationContext 接口:ApplicationContext 的子类,提供 配置 一个 应用上下文的 属性,如设置 environment,BeanFactoryPostProcessor,ApplicationListener,ProtocolResolver 等;

分析到这一步,我们发现Spring容器在这个方法中被实例化了。接下来,就让我们整理一下整体的思路:

当Servlet容器启动时,ServletContext对象被初始化,然后Servlet容器调用web.xml中注册的监听器的

public void contextInitialized(ServletContextEvent event)

方法,而在监听器中,调用了this.initWebApplicationContext(event.getServletContext())方法,在这个方法中实例化了Spring IOC容器。即ApplicationContext对象。

因此,当ServletContext创建时我们可以创建applicationContext对象,当ServletContext销毁时,我们可以销毁applicationContext对象。这样applicationContext就和ServletContext“共生死了”

Tomcat启动时,通过loadOnStartUp 的加载顺序(正整数小的先被加载)自动加载servlet

在servlet容器加载的的时候,会加载这个ServletConfig配置类,同时重写init方法中带参数的方法,可以得到ServletContext对象。

Servlet容器是整个servlet的运行环境,初始化整个servlet容器的时候就会初始化加载web.xml文件,同时也会创建整个类的全局变量ServletContext。

servlet初始化的过程中,会创建servlet对象,这个对象就是web.xml中配置的servlet类的相关信息。

ServletContext是JavaWeb四大域对象之一:

  • PageContext;一个页面

  • ServletRequest;一次请求

  • HttpSession; 一次会话

  • ServletContext;整个WEB应用 服务器开始,其就存在,服务器关闭,其才释放。

servlet tomcat 和spring的关系


用spring搭建的web项目里的service为何为空?
为什么servlet不能交给spring容器管理?
(无法注入)
servlet上下文存储spring容器

tomcat(web服务器(Servlet容器中有
Context:表示一个Web应用程序,对应着一个Servlet上下文(ServletContext),可以包含多个Wrapper;
Wrapper:表示一个独立的Servlet;

Servlet容器和ServletContext的关系:
ServletContext是servlet与servlet容器之间的直接通信的接口。Servlet容器在启动一个Web应用时,会为它创建一个servletContext对象。每个web应用有唯一的servletContext对象。同一个web应用的所有servlet对象共享一个serveltContext,servlet对象可以通过它来访问容器中的各种资源。 

ServletContext官方叫servlet上下文,服务器会为每一个工程创建一个对象,这个对象全局唯一,而且工程内部的所有servlet都共享这个对象。所以叫全局应用程序共享对象。


ApplicationContext是什么
ApplicationContext(spring容器)

Spring容器(父 )是管理service和dao的。
SpringMVC容器(子)是管理controller对象的。


XmlWebApplicationContext:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现

为什么要在web.xml注册监听器?

把spring容器放到全局作用域ServletContext中

使用监听器,当全局作用域被创建时,创建容器,放到ServletContext中

为什么要放全局作用域中?

容器对象需要在多个Servlet中使用,需要把容器对象放入到全局作用域ServletContext


因为监听器中要创建ApplicationContext对象,需要加载配置

监听器被创建后,会读取/WEB-INF/applicationContext.xml

目的是创建容器对象,创建了容器对象,就能把spring.xml配置文件中的所有对象都创建好,用户发起请求就可以直接使用对象


classpath:默认是从resource目录下


ConfigurableWebApplicationContext
继承
WebApplicationContext 
继承
ApplicationContext
从servletContext全局作用域中获取容器对象,webApplicationContext 再从容器对象中获取service对象


各个容器的创建过程:
1、TOMCAT启动,
Servlet容器随即启动,然后读取server.xml配置文件,启动里面配置的web应用,为每个应用创建一个“全局上下文环境”(ServletContext);
 
2、创建Spring容器实例。
调用web.xml中配置的ContextLoaderListener,初始化WebApplicationContext上下文环境(即IOC容器),加载context­param指定的配置文件信息到IOC容器中。WebApplicationContext在ServletContext中以键值对的形式保存。

3、创建SpringMVC容器实例。调用web.xml中配置的servlet-class,为其初始化自己的上下文信息,并加载其设置的配置信息到该上下文中。将WebApplicationContext设置为它的父容器。

4、此后的所有servlet的初始化都按照3步中方式创建,初始化自己的上下文环境,将WebApplicationContext设置为自己的父上下文环境。当Spring在执行ApplicationContext的getBean时,如果在自己context中找不到对应的bean,则会在父ApplicationContext中去找。

https://www.cnblogs.com/jieerma666/p/10805966.html


 

WebApplicationContext介绍 - 张秀杰 - 博客园 (cnblogs.com)

源码理解Spring中的各种context - 简书 (jianshu.com)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值