SpringMVC的实现源码分析

首先附上SpringMVC在web.xml中的基本配置

<?xml version="1.0"encoding="UTF-8"?>  
<web-app id="WebApp_ID" version="2.4"xmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eehttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
<listener>  
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
</listener>  
<context-param>  
<param-name>contextConfigLocation</param-name>  
<param-value>/WEB-INF/applicationContext.xml,/WEB-INF/controllers.xml,/WEB-INF/service.xml</param-value>  
</context-param>  
<servlet>  
<servlet-name>dispatch</servlet>  
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
<init-param>  
<param-name>contextConfigLocation</param-name>  
<param-value>/WEB-INF/applicationContext.xml</param-value>  
</init-param>  
</servlet>  
<servlet-mapping>  
<servlet-name>dispatch</servlet-name>  
<servlet-pattern>*.*</servlet-pattern>  
</servlet-mapping>  
</web-app> 

可以看出SpringMVC是基于servlet的,而这个servlet的核心类就是DispatcherServlet,我先给出DispatcherServlet的uml类图

分析一个servlet,肯定首要要从它的init方法开始,该方法在HttpServletBean里

@Override  
    public final void init() throws ServletException {  
        if (logger.isDebugEnabled()) {  
            logger.debug("Initializing servlet '" + getServletName() + "'");  
        }  
  
        // Set bean properties from init parameters.  
        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, this.environment));  
            initBeanWrapper(bw);  
            bw.setPropertyValues(pvs, true);  
        }  
        catch (BeansException ex) {  
            logger.error("Failed to set bean<span></span> properties on servlet '" + getServletName() + "'", ex);  
            throw ex;  
        }  
  
        // Let subclasses do whatever initialization they like.  
        initServletBean();  
  
        if (logger.isDebugEnabled()) {  
            logger.debug("Servlet '" + getServletName() + "' configured successfully");  
        }  
    }

在这段代码里面,try{}里面的代码负责的是<init-param>配置元素读取!

关键的是initServletBean()这个方法,这里的initServletBean()方法在HttpServletBean类中是一个没有任何实现的空方法,它的目的就是留待子类实现自己的初始化逻辑,也就是我们常说的模板方法设计模式,因此这个方法是存在于FrameworkServlet中的

@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 {  
        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");  
    }  
}
这个方法里面真正的核心是

this.webApplicationContext = initWebApplicationContext();
这段代码是用来建立容器上下文的
protected WebApplicationContext initWebApplicationContext()
 {
   WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
     WebApplicationContext wac = null;
    
    if (this.webApplicationContext != null)
    {
      wac = this.webApplicationContext;
      if ((wac instanceof ConfigurableWebApplicationContext)) {
      ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
       if (!cwac.isActive())
       {

        if (cwac.getParent() == null)
          {
           cwac.setParent(rootContext);
        }
      configureAndRefreshWebApplicationContext(cwac);
     }
       }
   }
    if (wac == null)
   {
   wac = findWebApplicationContext();
    }
     if (wac == null)
  {
     wac = createWebApplicationContext(rootContext);
  }
     
     if (!this.refreshEventReceived)
    {
       onRefresh(wac);
     }
   
    if (this.publishContext)
     {
       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;
  }
在这里面有一个onRefresh方法,这个方法用来初始化SpringMVC中的各种编程元素,该方法在DispatcherServlet中

@Override  
protected void onRefresh(ApplicationContext context) {  
    initStrategies(context);  
} 

protected void initStrategies(ApplicationContext context) {  
    initMultipartResolver(context);  
    initLocaleResolver(context);  
    initThemeResolver(context);  
    initHandlerMappings(context);  
    initHandlerAdapters(context);  
    initHandlerExceptionResolvers(context);  
    initRequestToViewNameTranslator(context);  
    initViewResolvers(context);  
    initFlashMapManager(context);  
} 
initMultipartResolver(context); //文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
initLocaleResolver(context); //本地化解析
initThemeResolver(context);   //主题解析
initHandlerMappings(context); //通过HandlerMapping,将请求映射到处理器
initHandlerAdapters(context); //通过HandlerAdapter支持多种类型的处理器
initHandlerExceptionResolvers(context); //如果执行过程中遇到异常将交给HandlerExceptionResolver来解析
initRequestToViewNameTranslator(context); //直接解析请求到视图名
initViewResolvers(context); //通过ViewResolver解析逻辑视图名到具体视图实现
initFlashMapManager(context); //flash映射管理器

这是每个方法的作用,在这里我 initHandlerMappings为例,分析一下

private void initHandlerMappings(ApplicationContext context) {  
        this.handlerMappings = null;  
  
        if (this.detectAllHandlerMappings) {  
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.  
            Map<String, HandlerMapping> matchingBeans =  
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);  
            if (!matchingBeans.isEmpty()) {  
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());  
                // We keep HandlerMappings in sorted order.  
                OrderComparator.sort(this.handlerMappings);  
            }  
        }  
        else {  
            try {  
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);  
                this.handlerMappings = Collections.singletonList(hm);  
            }  
            catch (NoSuchBeanDefinitionException ex) {  
                // Ignore, we'll add a default HandlerMapping later.  
            }  
        }  
  
        // Ensure we have at least one HandlerMapping, by registering  
        // a default HandlerMapping if no other mappings are found.  
        if (this.handlerMappings == null) {  
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);  
            if (logger.isDebugEnabled()) {  
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");  
            }  
        }  
    } 

回顾整个SpringMVC的初始化流程,我们看到,通过HttpServletBean、FrameworkServlet、DispatcherServlet三个不同的类层次,SpringMVC的设计者将三种不同的职责分别抽象,运用模版方法设计模式分别固定在三个类层次中。其中HttpServletBean完成的是<init-param>配置元素的依赖注入,FrameworkServlet完成的是容器上下文的建立,DispatcherServlet完成的是SpringMVC具体编程元素的初始化策略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值