Spring MVC源碼剖析 一、DispatcherServlet初始化源碼剖析

  使用Spring MVC的時候,每次都要在web.xml中初始化一個DispatcherServlet,這是爲什麼呢?因爲我們需要DispatcherServlet來將Spring容器啓動起來,啓動完成後,由DispatcherServlet來接收請求並分發。

  首先。DispatcherServlet 繼承 FrameworkServlet,FrameworkServlet 繼承 HttpServletBean ,HttpServletBean 繼承 HttpServlet ,即原生的 HttpServlet 。

  我們下面看一下DispatcherServlet的初始化過程:

  系統new了 DispatcherServlet 了之後,會調用其init() 方法,即 HttpServletBean 的init方法:

@Override
	public final void init() throws ServletException {

		// 從配置文件中讀取出配置,比如在web.xml中讀取的 name爲contextConfigLocation,value爲 classpath*:servlet-context.xml
		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) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}

		// 此方法非常非常重要,初始化容器,與web中的相關映射。
		initServletBean();

	}

繼續看 FrameworkServlet中的 initServletBean() 方法:

	protected final void initServletBean() throws ServletException {
		

		long startTime = System.currentTimeMillis();

		try {
			// 此方法非常重要,初始化了一個 ApplicationContext 容器,完成了beanDefinition的生成,根據beanDefinition生成bean的操作
 // 在bean生成完成之後,此方法還會初始化 mvc 中的 HanderMapping、handerAdapter等一系列組件
			this.webApplicationContext = initWebApplicationContext();

		}
		
		. . . 

		if (this.logger.isInfoEnabled()) {
			// 還會計時,我們平常的計時就在這裏來完成的
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}

   再看一下 initWebApplicationContext() 方法:

	protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		. . . 
		
		if (wac == null) {
			// 此爲創建一個 WebApplicationContext ,並調用其 refresh() 方法來生成容器
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// 此爲調用自身的 onRefresh() 方法,來初始化  mvc 中的 HanderMapping、handerAdapter等一系列組件
			onRefresh(wac);
		}

		. . .
		return wac;
	}

  首先看一下 createWebApplicationContext() ,看其實如何來生成一個 容器 的:

	protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		

		// 先使用 BeanUtils 生成了一個 ApplicationContext,注意我們生成的是 XmlWebApplicationContext
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);

		// 此爲將 context 文件的路徑注入進去,比如我們之前使用的xmlClassPathApplicationContext,就需要一個 xml 文件的路徑,現在也是一樣的,通過這個將其注入進去
		wac.setConfigLocation(getContextConfigLocation());

		// 最後調用方法將其初始化完成
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {

		. . .

		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}

		postProcessWebApplicationContext(wac);
		applyInitializers(wac);

		// 注意,最後非常重要!調用了 applicationContxt的 refresh() 方法,先根據ConfigLocation得到Resource,在根據Resource生成beanDefinition,最後根據 beanDefinition 生成bean。
		wac.refresh();
	}

  至此,Spring容器啓動。

 

 

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