springMVC初始化和流程(二)

一、Spring MVC初始化配置

  上一篇已经介绍了Spring MVC的执行流程。这篇主要介绍Spring MVC 的初始化。Spring MVC的配置一般是在web.xml中配置系统变量contextConfigLocation和DispatcherSevlet,配置内容如下:

配置方法一:通过初始化DispatcherServlet然后初始化contextConfigLocation
<!--
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:spring/spring-*.xml</param-value>   </init-param>   <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping>   <servlet-name>SpringMVC</servlet-name>   <url-pattern>*.do</url-pattern> </servlet-mapping> 配置方法二: <!-- 配置SpringMVC 配置文件路径 --> <context-param>   <param-name>contextConfigLocation</param-name>   <param-value>/WEB-INF/spring-configuration/*.xml</param-value> </context-param> <!-- 配置ContextLoaderListener用以消除还换Spring Ioc 容器--> <listener>   <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置ContextLoaderListener用以消除还换Spring Ioc 容器--> <servlet>   <servlet-name>SpringMVC</servlet-name>   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>   <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping>   <servlet-name>SpringMVC</servlet-name>   <url-pattern>*.do</url-pattern> </servlet-mapping>

配置内容:

• 系统变量contextConfigLocation的配置告诉Spring MVC 其Spring Ioc的配置文件在哪里,这样Spring会找到这些配置文件去加载它们。多个文件可用逗号隔开,正则匹配。

• ContextLoadListener实现了接口ServletContextListener,可在WEB工程初始化之前,完成对Spring Ioc 容器的初始化,也可在WEB工程关闭之时完成Spring Ioc容器的资源释放。

• 配置DispatcherServlet,初始化映射请求上下文。

二、Spring MVC 初始化

  由上面配置文件的配置内容就可看出,Spring MVC 的初始化包含初始化Spring Ioc上下文和初始化映射请求上下文两个步骤,只是映射请求上下文是基于Spring Ioc上下文扩展出来的,以适应Java Web工程的需要。

1、初始化Spring Ioc上下文

Java Web 容器为其生命周期中提供ServletContextListener接口,这个接口可以在Web容器初始化和结束期中执行一定逻辑。通过它可以在DispatcherServlet初始化之前完成Spring Ioc容器的初始化,也可以在结束完成对Spring Ioc容器的销毁,只需要实现ServletContextListener接口的方法就可以。

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

  @Override
  public void contextInitialized(ServletContextEvent event) {
    //初始化Spring IOC容器-       initWebApplicationContext(event.getServletContext());   }   @Override   
public void contextDestroyed(ServletContextEvent event) {
    //关闭web Ioc容器     closeWebApplicationContext(event.getServletContext());
    //清除相关参数     ContextCleanupListener.cleanupAttributes(event.getServletContext());   } }

2、初始化映射请求上下文

  映射请求上下文是通过DispatcherServlet初始化的,它和普通的Servlet也是一样的。如果在WEB工程中并没有注册ContextLoadListener,这个时候DispatcherSerclet就会在其初始化的时候对Spring Ioc容器进行初始化。

  初始化一个Spring Ioc容器是耗时操作,如果放大用户请求上,会让一个用户陷入长时间的等待,因此一般在WEB容器启动的时候,或Web 容器载入DispatcherServlet的时候就初始Spring Ioc容器。所以一般建议使用ContextLoadListener进行初始化。

图一、DispatcherServlet 的设计

  Web 容器对于Servlet的初始化,首先调用其ini方法,对于DispatcherServlet也是如此,这个方法位于其父类HttpServletBean里如下:

代码一:HttpServletBean中init方法

  @Override
    public final void init() throws ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("Initializing servlet '" + getServletName() + "'");
        }
        // Set bean properties from init parameters.
    //根据参数初始化Bean
        try {
            PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        }
        catch (BeansException ex) {
            if (logger.isErrorEnabled()) {
                logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
            }
            throw ex;
        }
        // Let subclasses do whatever initialization they like.
    //初始化Servletbean,这个方法交由子类FramworkServlet实现,接着看代码清单二中实现
        initServletBean();

        if (logger.isDebugEnabled()) {
            logger.debug("Servlet '" + getServletName() + "' configured successfully");
        }
   

代码清单二:framworkServlet中的initServletBean方法实现

@Override
    protected final void initServletBean() throws ServletException {
        getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
        if (this.logger.isInfoEnabled()) {
            this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
        }
        long startTime = System.currentTimeMillis();

        try {
        //初始化Spring Ioc容器
            this.webApplicationContext = initWebApplicationContext();
            initFrameworkServlet();
        }
        catch (ServletException ex) {
            this.logger.error("Context initialization failed", ex);
            throw ex;
        }
        catch (RuntimeException ex) {
            this.logger.error("Context initialization failed", ex);
            throw ex;
        }

        if (this.logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
                    elapsedTime + " ms");
        }
    }

protected WebApplicationContext initWebApplicationContext() {
  WebApplicationContext rootContext =
  WebApplicationContextUtils.getWebApplicationContext(getServletContext());
  WebApplicationContext wac = null;
  //判断Spring  Ioc容器是否已经初始化
  if (this.webApplicationContext != null) {
    // A context instance was injected at construction time -> use it
    //如果Web Ioc容器已经在启动的时候创建,那么就沿用它
    wac = this.webApplicationContext;     if (wac instanceof ConfigurableWebApplicationContext) {       ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;       if (!cwac.isActive()) {         // The context has not yet been refreshed -> provide services such as         // 如果Spring Ioc容器还没有刷新,那么久进行刷新父容器上下文,设置ID等操作         if (cwac.getParent() == null) {           // The context instance was injected without an explicit parent -> set           // 处理父容器为空的情况           cwac.setParent(rootContext);         }         configureAndRefreshWebApplicationContext(cwac);        }     }   }   if (wac == null) {   // No context instance was injected at construction time -> see if one   // has been registered in the servlet context. If one exists, it is assumed   // that the parent context (if any) has already been set and that the   // 没有被初始化,则查找是否存在Spring Web Ioc容器     wac = findWebApplicationContext();   }   if (wac == null) {     // 没有被初始化也没有被找到Spring Ioc容器,则DispatcherServlet自己创建     wac = createWebApplicationContext(rootContext);   }   if (!this.refreshEventReceived) {     // Either the context is not a ConfigurableApplicationContext with refresh     // support or the context injected at construction time had already been     // 当onRefresh方法没有被调用过,执行onRefresh方法,这个方法在DispatcherServlet中,参加代码清单三     onRefresh(wac);   }   if (this.publishContext) {     // Publish the context as a servlet context attribute.     String attrName = getServletContextAttributeName();     getServletContext().setAttribute(attrName, wac);     if (this.logger.isDebugEnabled()) {       this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +       "' as ServletContext attribute with name [" + attrName + "]");     }   }   return wac; }

代码清单三:DispatcherServlet中初始化Spring MVC的组件

/**
     * This implementation calls {@link #initStrategies}.
     */
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    /**
     * Initialize the strategy objects that this servlet uses.
     * <p>May be overridden in subclasses in order to initialize further strategy objects.
     */
    protected void initStrategies(ApplicationContext context) {
        //初始化文件的解析
        initMultipartResolver(context);
        //本地解析化
        initLocaleResolver(context);
        //主题解析
        initThemeResolver(context);
        //处理器映射
        initHandlerMappings(context);
        //处理器的适配器
        initHandlerAdapters(context);
        //Handler 的异常处理器
        initHandlerExceptionResolvers(context);
        //当处理器没有返回逻辑视图名等相关信息时,自动将请求URL映射为逻辑视图名
        initRequestToViewNameTranslator(context);
        //视图逻辑名称转换器,即允许返回逻辑视图名称,然后它会找到真实的视图
        initViewResolvers(context);
        //
        initFlashMapManager(context);
    }

以上是Spring MVC主要组件的初始化,实际上,对这些组件的初始化会根据配置文件DispatcherServlet.properties来进行初始化

猜你喜欢

转载自www.cnblogs.com/huif/p/11106311.html