springmvc之初始化

1.核心接口

dispatchServlet UML圖:

DispatchServlet,httpservletBean,FrameWorkServlet這三個類直接實現了EnvironmentCapable,EnvironmentAware以及ApplicationContextAware接口.

科普:

①:XXXAwaare在spring裏表示對XXX感知,也就是:如果在某個類裏面想要使用spring的一些東西,就可以通過實現XXXAware接口告訴spring,spring看到後就會給你送過來,而接收的方式是通過實現接口唯一的方法setXXX().比如:有個類想要使用當前的applicationContext,我們只需要讓他實現ApplicationContextAware接口,然後實現接口中唯一的方法,void setApplicationContext(ApplicationContext applicaitonContext)就可以了,spring會自動調用這個方法將applicationContext傳過來.

②:XXXCapable在spring中就是具有XXX的能力,比如:EnvironmentCapable就是告訴spring,他有提供Environment的能力,EnvironmentCapable唯一的方法及時Environment getEnvironment()當;spring需要Environment時,就會調用其get方法跟他要.

springmvc啓動

httpServletBean

DispatchServlet創建時,可以直接調用無參的init方法,dispatchServlet默認調用httpServletbean的init方法,如下:(篇幅有點長,省略try…catch)

 public final void init() throws ServletException {
 		//將servlet中配置的參數封裝到pvs中,requireProperties爲必須參數,沒有將拋出ServletException
        PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
        if (!pvs.isEmpty()) {
                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
                bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
                //模板方法,可以在子類中調用,做一些初始化工作(默認空實現).這裏的bw代表Dispatchservlet;
                this.initBeanWrapper(bw);
                //通過beanWrapper將配置的初始化值(如:contextConfigLocation屬性)設置到dispatchServlet中;
                bw.setPropertyValues(pvs, true);
        //模板方法,子類初始化的方法入口.這裏做個空實現,具體實現在FrameWorkServlet中.
        this.initServletBean();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
        }
    }

FrameWorkServlet

從httpServletBean中可知,FrameworkServlet的初始化入口方法是initservletBean().方法代碼如下:

//去除try..catch以及日誌打印代碼,其核心只做了兩件事情
 protected final void initServletBean() throws ServletException {
 			// 1.初始化WebApplcationContext(ConfigurableWebApplicationContext)
            this.webApplicationContext = this.initWebApplicationContext();
            // 2.初始化FrameworkServlet,次方式爲模板方法,空實現,子類Dispatchservlet並沒有使用它
            this.initFrameworkServlet();
 }

可見frameworkservlet在構建過程中的主要作用就是初始化WebApplicationContext,下面爲initWebApplicationContext代碼:

 protected WebApplicationContext initWebApplicationContext() {
 		//獲取rootContext
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        //如果已經通過構造方法設置了WebApplicationContext
        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);
                    }
                    this.configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
        	//當webApplicationContext已經存在於servletContext中,通過配置在servlet中的contextAttribute獲取
            wac = this.findWebApplicationContext();
        }
        if (wac == null) {
        	//如果webApplicationContext還沒有,則創建一個,一般情況都是調用 這個創建.
            wac = this.createWebApplicationContext(rootContext);
        }
        if (!this.refreshEventReceived) {
        	//模板方法,當ContextRefreshedEvent事件沒有觸發時調用此方法,在子類dispatchServlet中具體實現.
            this.onRefresh(wac);
        }
        if (this.publishContext) {
        	//將ApplicationContext設置到servletContext中,
            String attrName = this.getServletContextAttributeName();
            this.getServletContext().setAttribute(attrName, wac);
        }
        return wac;
    }

主要分析一下createWebApplicationContext(rootContext) 方法,貼代碼:

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		//獲取創建類型
        Class<?> contextClass = this.getContextClass();
     	//檢查創建類型( A.class.isAssignableFrom(B.class):判斷A是不是B的超類) contextclass 默認爲XmlWebApplicationContext
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
        } else {
			//默認會走這裏
            ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
            wac.setEnvironment(this.getEnvironment());
            wac.setParent(parent);
            //將設置的contextConfigLocaltion傳遞給wac
            wac.setConfigLocation(this.getContextConfigLocation());
			//這裏面添加了應用 監聽器,ContextRefreshListener
            this.configureAndRefreshWebApplicationContext(wac);
            return wac;
        }
    }

ContextRefreshListener是FrameWorkServlet的內部類

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
		@Override
		public void onApplicationEvent(ContextRefreshedEvent event) {
			FrameworkServlet.this.onApplicationEvent(event);
		}
}
	public void onApplicationEvent(ContextRefreshedEvent event) {
		this.refreshEventReceived = true;
		//模板方法,在子類dispatchservlet中具體實現
		onRefresh(event.getApplicationContext());
	}

DispatchServlet

onRefresh 方法是Dispatchservlet的入口方法,onrefresh中調用了initStrategies,在initstrategies中調用了9個方法.

//org.springframework.web.servlet.DispatcherServlet
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);
}

這裏9個初始化方法都類似,這裏以初始化handlerMapping 爲例,

private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
		//首先在applicationContext中獲取
		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.
				AnnotationAwareOrderComparator.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.
			}
		}
		//如果沒有自定義handlermapping,則使用默認策略
		if (this.handlerMappings == null) {
			//加載默認策略
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}

下面介紹一下getDefaultStrategies 這個方法,貼代碼:
從這段代碼可以看出:默認策略返回的是個集合,集合如果不爲空,則直接返回了集合中的第一個策略配置.

	//strategyInterface 爲HandlerMapping.class
	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		//從defaultStrategies中獲取該策略的值
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			//多個值之間用逗號分隔
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<T>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
						// ... 省略
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<T>();
		}
	}
defaultStrategies ? springmvc都有哪些默認的策略配置?

繼續貼代碼,springmvc從默認的DispatcherServlet.properties文件中加載默認策略

	//org.springframework.web.servlet.DispatcherServlet
	private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
	private static final Properties defaultStrategies;
	static {
		try {
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
		}
	}
DispatcherServlet.properties 文件,看看就行了,默認加載第一個配置的
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
springmvc創建完成!

後續更新springmvc怎樣處理請求

FrameworkServlet中的模板方法doService在其子類中Dispatchservlet中的具體實現,以及springmvc,通過request獲取hangler,根據handler找到對應的handlerAdapt,用handler處理handler,調用processDispatchResult方法處理上面返回的結果(包含找到view並輸出渲染給用戶),並展示給用戶.

概念:

handler:也就是處理器,mvc中的c,可以是類,也可以是方法,所有標註了@RequestMapping註解的方法都可以看成一個handler,只要可以處理請求,那就是一個handler.

handlerMapping:也就是處理器映射器,用來查找handler的,springmvc 會處理很多請求,每個請求都需要一個handler來處理,具體接收到一個請求後需要哪個handler來處理,這就是handlerMapping要做的事情.

handlerAdapt:也就是處理器適配器,springmvc 的handler可以是任意形式,而servlet處理請求的結構卻是固定的,如:doService方法,怎麼讓固定的servlet處理靈活的Handler就是handlerAdapt做的事情.

***不確定有沒有後文,所以多加了點常識! ***

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章