SpringMVC和Servlet

Posted by RussXia on August 8, 2019

SpringMVC和Servlet

HTTP服务器将请求发到Servlet容器,Servlet容器会将请求转发到具体的Servlet,如果此Servlet尚未创建,则加载并实例化这个Servlet(init方法),然后调用这个Servelt的service方法,真正处理请求。 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();
}

上面是Servlet接口定义的五个方法。

  • initdestory方法描述了这个Servlet创建和销毁时应该做的一些动作。Servlet容器在加载Servlet容器的时候,会调用init方法;在卸载的时候,会调用destroy方法。
  • getServletInfo方法,主要用于返回此Servlet的一些信息,包括author、version、copyright等等。
  • getServletConfig方法,返回ServletConfig对象,ServletConfig对象包含了Servlet的初始化参数。
  • service方法,由Servlet容器调用,处理请求。方法只可能在servlet成功init后才可以被调用。

Servlet是网络处理,请求抽象的封装,针对Http协议的实现,对应的Servlet实现类就是javax.servlet.http.HttpServletHttpServlet只处理参数格式是HttpServletRequestHttpServletResponse的请求。HttpServletRequestHttpServletResponse表示HTTP协议中的请求和响应。Service方法,会根据HTTP请求的请求方法,调用doGetdoPost等方法处理。

每个web应用都会创建一个全局唯一的ServletContext对象,你可以通过Servletontext来共享Servlet数据,ServletContext是线程不安全的,Tomcat中的实现是org.apache.catalina.core.ApplicationContext。在分布式环境中,由于每个VM中都会有一个ServletContext,无法做到全局共享一个context,建议使用db代替。

filter过滤器 和 listner监听器

filter过滤器,在Web应用部署完成后,Servlet容器会实例化filter,并把filter连接成一个FilterChain(链表)。当请求进来时,获取第一个filter,并调用doFilter方法

Filters use the FilterChain to invoke the next filter in the chain, or if the calling filter is the last filter in the chain, to invoke the resource at the end of the chain.

Listener监听器,主要用于监听某些特定的事件,当特定事件发生时,Servlet容器回负责调用监听器的方法。 Servlet的事件监听接口有8个:

  • ServletContextListener:用于监听 ServletContext 的启动和销毁。
  • ServletContextAttributeListener:用于监听 ServletContext 属性的变化(add/remove/replace)。
  • HttpSessionListener:用于监听 session 的创建和销毁。
  • HttpSessionIdListener:用于监听 session 的 id 是否被更改。(使用的很少,不清楚什么样的属于)
  • HttpSessionAttributeListener:用于监听 session 范围的属性变化(add/remove/replace)。
  • HttpSessionActivationListener:用于监听绑定在 HttpSession 对象中的 JavaBean 状态。
  • HttpSessionBindingListener:用于监听对象与 session 的绑定和解绑。
  • ServletRequestListener:用于监听 ServletRequest 对象的初始化和销毁。
  • ServletRequestAttributeListener:用于监听 ServletRequest 对象的属性变化。 HTTP请求处理流程

SprinMVC

<!-- 配置启动参数->spring xml入口,加载spring容器-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext.xml</param-value>
</context-param>

<!-- Servlet容器启动和销毁时触发的时间,加载spring容器的入口 -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- DispatcherServlet:SpringMVC的核心,负责加载SpringMVC容器,请求的处理转发 -->
<servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<!-- 交给SpringMVC这个Servlet处理的路由请求 -->
<servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

SpringMVC的启动过程

我们在配置SpringMVC的时候,会配置一个Listener:org.springframework.web.context.ContextLoaderListener,这个ContextLoaderListener实现了ServletContextListener接口,所以当Servlet容器启动的时候,会触发事件,然后调用org.springframework.web.context.ContextLoaderListener#contextInitialized方法。

ContextLoaderListener类的部分源码:

/**
  * Initialize the root web application context.
  */
@Override
public void contextInitialized(ServletContextEvent event) {
    //创建spring web容器(这是spring ROOT容器)
    initWebApplicationContext(event.getServletContext());
}

在创建完成Spring的 web application context 后,会将其保存到ServletContext中,方便获取。

Servlet一般是会延迟加载,但是我们配置了load-on-startup为1,当load-on-startup的value>=0时,容器必须在部署后加载这个Servlet。Tomcat/Jetty发现DispatcherServlet还没有被实例化,就会调用DispatcherServlet的init方法。

DispatcherServlet会初始化自己的IoC上下文(Spring MVC容器),并将Spring的application context作为自己的父级contextDispatcherServlet初始化的,主要是我们本例中定义在springmvc.xml中配置的bean(一般都是扫描controller这类bean,各类解析器bean等)以及org.springframework.web.servlet.DispatcherServlet#initStrategies初始化的一些策略。如视图解析器,请求和处理的映射(mapping),异常处理器等等。

关于ServletContext,Spring容器,SpringMVC容器的总结

Tomcat在启动时会为Web应用创建一个全局的上下文环境,这个就是ServletContext。启动web应用时,ContextLoaderListener会读取配置的xml文件,初始化Spring容器,并将其保存到ServletContext中。然后在初始化DispatcherServlet时,会初始化SpringMVC容器,并从ServletContext容器中获取Spring容器,并将Spring容器作为自己的parent容器,最后DispatcherServlet会将初始化好的SpringMVC容器也保存到ServletContext中。

因为Spring容器和SpringMVC容器是两个容器,Spring容器是SpringMVC容器的parent,所以在SpringMVC容器中,可以获取到Spring容器中的Bean。而在Spring容器中不能获取到SpringMVC中的bean。