1. 程式人生 > >SpringMVC原始碼剖析(一) DispatcherServlet

SpringMVC原始碼剖析(一) DispatcherServlet

一、DispatcherServlet構造方法

DispatcherServlet有兩個構造方法,一個無引數的構造方法和一個WebApplicationContext引數的構造方法,如下程式碼:

    public DispatcherServlet() {
    }

    public DispatcherServlet(WebApplicationContext webApplicationContext) {
        super(webApplicationContext);
    }

其中重點看有引數的構造方法,其主要是呼叫其父類的構造方法,DispatcherServlet是繼承父類FrameworkServlet,我們看下FrameworkServlet的構造方法,其程式碼如下:

    public FrameworkServlet(WebApplicationContext webApplicationContext) {
        this.contextClass = DEFAULT_CONTEXT_CLASS;
        this.publishContext = true;
        this.publishEvents = true;
        this.threadContextInheritable = false;
        this.dispatchOptionsRequest = false;
        this.dispatchTraceRequest = false;
        this.webApplicationContextInjected = false;
        this.refreshEventReceived = false;
        this.contextInitializers = new ArrayList();
        this.webApplicationContext = webApplicationContext;
    }

其中DEFAULT_CONTEXT_CLASS是XmlWebApplicationContext的類,主要是對其中一些屬性進行賦值。

二、屬性設定

DispatcherServlet通過set方法設定了一些屬性,這些屬性的預設值都為true,如下:

1、detectAllHandlerMappings           

2、detectAllHandlerAdapters

3、detectAllHandlerExceptionResolvers

4、detectAllViewResolvers

5、throwExceptionInfoHandlerFound

6、cleanupAfterInclude

三、初始化

DispatcherServlet中有一個onRefresh方法,其主要呼叫的是initStrategies(context)方法

再看一下initStrategies(context)方法的原始碼

    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

主要做的是一些檔案上傳解析器,HandlerMappings等的一些初始化,會呼叫這些元件的私有初始化方法進行初始化。

例如檔案上傳解析器初始化initMultipartResolver方法

   private void initMultipartResolver(ApplicationContext context) {
        try {
            this.multipartResolver = (MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
            }
        } catch (NoSuchBeanDefinitionException var3) {
            this.multipartResolver = null;
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided");
            }
        }

    }

首先從context中通過getBean方法獲取一個multipartResolver物件,並賦值到DispatcherServlet中的mutipartResolver屬性中。如果出現異常,會將mutipartResolver屬性設為空,並且列印日誌。

方法initLocaleResolver和initThemeResolver和其類似。

看一下方法initHandlerMappings(ApplicationContext context)

    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        if (this.detectAllHandlerMappings) {
            Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                OrderComparator.sort(this.handlerMappings);
            }
        } else {
            try {
                HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            } catch (NoSuchBeanDefinitionException var3) {
                ;
            }
        }

        if (this.handlerMappings == null) {
            this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("No HandlerMappings found in servlet '" + this.getServletName() + "': using default");
            }
        }

    }

首先將handlerMappings設定為空,建立了一個Map<String,HandlerMapping>,String和HandlerMapping的key-value的map,通過BeanFactoryUtils的方法beansOfTypeIncludingAncestors,這個方法的作用是根據型別尋找bean,找出所有匹配型別的beanName,取出匹配bean的值,放入handlerMappings的ArrayList陣列中,並且進行排序,這個排序底層呼叫的是Collections.sort()的方法,傳入了一個OrderComparator的比較器。

如果沒有找到handlerMapping,會使用一個預設的BeanNameUrlHandlerMapping,確保有至少有一個HandlerMapping

四、get方法

DispatcherServlet定義了獲取這些屬性的get方法

五、預設策略方法

建立一個預設的策略,其預設實現使用AutoworeCapableBeanFactory的createBean方法

	protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
		return context.getAutowireCapableBeanFactory().createBean(clazz);
	}