SpringMVC与Web解读(一):SpringMVC环境构建与ContextLoaderListener

来源:互联网 发布:数据库黑客大曝光 编辑:程序博客网 时间:2024/06/06 01:28

写在前面:阅读需要会使用SpringMVC

Web环境中的SpringMVC:概述

在Web环境中,SpringMVC是建立在IoC容器上的。了解SpringMVC,首先要了解SpringIoC容器是如何在Web环境中被载入的。Spring IoC是一个独立的模块,它并不是在Web容器中发挥作用的,如果要在Web容器中使用IoC容器,需要Spring为IoC设计一个启动过程,吧IoC容器导入,并在Web容器中建立起来。这个启动过程需要结合Web容器的启动过程。一方面处理Web容器的启动,另一方面通过设计特定的Web容器拦截器,将IoC容器载入到Web环境中,并将其初始化。在这个过程完成之后,IoC容器才能够正茬工作,才能建立起MVC框架的运行机制,从而响应容器传递的HTTP请求。

在Web.xml的设置中,有两个设置,一个是DispatcherServlet,另一个是ContextLoaderListener。DispatcherServlet负责响应处理HTTP请求,ContextLoaderListener负责构建SringMVC建立一个IoC容器在Web环境中的启动工作。

ContextLoaderListener和IoC容器的构建

ContexLoaderListener
web.xml中部署ContextLoaderListener:

<listener>    <listener-class>            org.springframework.web.context.ContextLoaderListener    </listener-class></listener>

监听器:ContextLoaderListener这个监听器是和Web服务器的生命周期相关联的,由ContextLoaderListener负责完成IoC容器在Web环境中的启动工作,如将DispatchServlet作为SpringMVC处理Web请求的转发器的建立过程等。
它实现了ServletContextListener接口。该定义在Servlet API中,提供了如contextInitialized和ContextDestroyed等方法。

ContextLoaderListener的组成

在Web容器中,建立WebApplicationContext的过程,是在 contextInitialized的接口中实现的,而具体的载入IoC容器的过程是由ContextLoaderListener交由ContextLoader来完成的。ContextLoader是ContextLoaderListener的基类。类图如下:

这里写图片描述

IoC容器启动的基本过程 :
这里写图片描述

Web容器的上下文设计

先看上下文(Context)设计,再从ContextLoaderListener中去了解整个容器启动的过程。在Web环境中,Spring提供了WebApplicationContext来满足启动过程的需要,WebApplicationContext是我们观察的重点。
WebApplication的类层次图如下所示:

这里写图片描述
在这个接口设计中,有ApplicationContext和BeanFactory进行对接。在这里,XmlWebApplicationContext是我们比较熟悉的对象,它在ApplicationContext的继承功能上,增加了对Web环境和XML配置定义的处理。在启动过程中,Spring会使用一个默认的WebApplicationContext实现作为IoC容器,这个默认实现是XmlWebApplicationContext,其默认读取的配置文件是:/WEB-INF/applicationCointext.xml

ContextLoader的设计和实现

对于Spring承载的Web应用而言,IoC容器的载入和初始化是由ContextLoaderListener这样的类来完成的。ContextLoaderListener实现了ServletContextListener接口,这个接口里的函数会结合Web的容器声明周期被调用,如初始化和销毁。具体的初始化,有ContextLoader来完成

ContextLoader的初始化工作

ContextLoader主要完成根上下文(root context,作为Web容器中唯一的实例而存在,单例的意思吧)在Web容器的创建,并将其保存到Web容器的ServletContext中,供需要时使用。
初始化代码

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {   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!");   }   Log logger = LogFactory.getLog(ContextLoader.class);   servletContext.log("Initializing Spring root WebApplicationContext");   if (logger.isInfoEnabled()) {      logger.info("Root WebApplicationContext: initialization started");   }   long startTime = System.currentTimeMillis();   try {      // Store context in local instance variable, to guarantee that      // it is available on ServletContext shutdown.      if (this.context == null) {         this.context = createWebApplicationContext(servletContext);      }      if (this.context instanceof ConfigurableWebApplicationContext) {         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;         if (!cwac.isActive()) {            // The context has not yet been refreshed -> provide services such as            // setting the parent context, setting the application context id, etc            if (cwac.getParent() == null) {               // The context instance was injected without an explicit parent ->               // determine parent for root web application context, if any.               ApplicationContext parent = loadParentContext(servletContext);               cwac.setParent(parent);            }            configureAndRefreshWebApplicationContext(cwac, servletContext);         }      }//设置root_context      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.isDebugEnabled()) {         logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +               WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");      }      if (logger.isInfoEnabled()) {         long elapsedTime = System.currentTimeMillis() - startTime;         logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");      }      return this.context;   }   catch (RuntimeException ex) {      logger.error("Context initialization failed", ex);      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);      throw ex;   }   catch (Error err) {      logger.error("Context initialization failed", err);      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);      throw err;   }}

创建Web上下文

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {//这里判断使用什么样的类作为IoC容器   Class<?> contextClass = determineContextClass(sc);   if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {      throw new ApplicationContextException("Custom context class [" + contextClass.getName() +            "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");   }   return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);}

确定使用的IoC容器

protected Class determineContextClass(ServletContext servletContext) thorws ApplicationContextException{    //读取ServletContext中对CONTEXT_CLASS_PARAM参数的配置 String contextClassName = servletContext.getInitParmamter(CONTEXT_CLASS_PARAM);//如果设置了需要使用的上下文类,就用这个类if(contextClassName != null){      try{        return ClassUtils.forName(contextClassName,ClassUtils.getCDefaultClassLoader());      catch(ClasssNotFountException ex){            //抛出异常信息       }else{//没有设置,使用默认的contextClass类    contextClassName = defaultStategies.getProperty(WebApplicationContext.class.getName());    try{        return ClassUtils.forName(contextClassName,ClassUtils.getCDefaultClassLoader());      catch(ClasssNotFountException ex){            //抛出异常信息       } }}
阅读全文
0 0
原创粉丝点击