溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何進行SpringMVC源碼中的初始化源碼

發(fā)布時間:2021-12-27 14:00:06 來源:億速云 閱讀:198 作者:柒染 欄目:互聯(lián)網(wǎng)科技

如何進行SpringMVC源碼中的初始化源碼,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

所有Java的MVC框架都是基于servlet的,SpringMVC也不例外。它提供核心控制器DispatcherServlet,并且在此Servlet實例化后做出一系列的初始化處理,從而保證后期的高效率運行。在研究源碼之前,我們首先看一下DispatcherServlet的繼承結(jié)構(gòu)。這三個Servlet類是SpringMVC的核心控制器類,各負其職來完成SpringMVC的各項功能。

其中,HttpServletBean主要做一些初始化的工作,將web.xml中配置的參數(shù)設(shè)置到核心控制器Servlet中,比如servlet標簽的初始化參數(shù)子標簽init-param標簽中配置的參數(shù);

FrameworkServlet將Servlet與Spring容器上下文關(guān)聯(lián)。其實也就是初始化FrameworkServlet的屬性webApplicationContext,這個屬性代表SpringMVC上下文,其實也就是spring技術(shù)中web.xml配置的ContextLoaderListener監(jiān)聽器初始化的容器上下文,所以我們也說SpringMVC是基于Spring的;

DispatcherServlet完成SpringMVC對web請求各個功能的實現(xiàn)。比如請求映射處理、視圖處理、異常處理等。

    任何web功能的實現(xiàn)都是從web.xml開始的,所以我們先來看看web.xml中的配置:

        <servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

這里配置了SpringMVC核心處理器,并且傳遞了參數(shù)contextConfigLocation以指定SpringMVC核心配置文件的位置,在服務(wù)器啟動時進行加載并實例化。

    HttpServletBean覆蓋了init()方法,所有初始化處理都是此Servlet實例化之后于init方法中完成的,下面我們就來看看其中三個最主要信息的初始化:讀取初始化參數(shù)contextConfigLocation、構(gòu)造SpringMVC容器、創(chuàng)建所有的Bean對象。

public final void init() throws ServletException {
		//......
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);//從ServletConfig中獲取初始化參數(shù)(如contextConfigLocation=classpath:springmvc.xml等)
		if (!pvs.isEmpty()) {
			try {
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);//構(gòu)造BeanWrapper對象,接下來就是由BeanWrapper完成初始化處理
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				initBeanWrapper(bw);
				bw.setPropertyValues(pvs, true);//把初始化參數(shù)contextConfigLocation設(shè)置到核心控制器DispatcherServlet的contextConfigLocation屬性中.
			}
			catch (BeansException ex) {
				//...
			}
		}
		initServletBean();//這個方法在本類中是空實現(xiàn),它用來是被子類(FrameworkServlet)覆蓋的,在子類中進行構(gòu)造SpringMVC容器上下文對象,這也是模板設(shè)計模式的具體應(yīng)用。
		//......
	}

    下面先來看BeanWrapper是如何設(shè)置初始化參數(shù)的:從源碼我們會看到,BeanWrapper是個接口,實現(xiàn)類是BeanWrapperImpl,BeanWrapperImpl是AbstractNestablePropertyAccessor的子類,AbstractNestablePropertyAccessor有個屬性wrappedObject,保存了核心控制器的引用,那么BeanWrapperImpl類也具有對DispatcherServlet對象的引用。在BeanWrapperImpl中有一個方法setValue()用來保存初始化參數(shù)到DispatcherServlet的屬性中:

setValue(final Object object, Object valueToApply)
	         //......
			if (System.getSecurityManager() != null) {
				//......
			}
			else {
				writeMethod.invoke(getWrappedInstance(), value);//這里使用反射把獲取到的初始化參數(shù)contextConfigLocation核心控制器的屬性contextConfigLocation。
			}
		//......
	}

    其實,SpringMVC本身能用到的初始化參數(shù)也就是contextConfigLocation了。

    接下來我們來看看FrameworkServlet類的initServletBean()方法如何構(gòu)造SpringMVC容器上下文對象:FrameworkServlet是HttpServletBean的子類,它覆蓋了initServletBean()方法,主要用來在服務(wù)器啟動時構(gòu)造SpringMVC容器上下文對象。

protected final void initServletBean() throws ServletException {
			//......
			try {
				this.webApplicationContext = initWebApplicationContext();//創(chuàng)建出SpringMVC容器對象
				initFrameworkServlet();
			}
			//......
		}

    很顯然,調(diào)用initWebApplicationContext()方法創(chuàng)建出SpringMVC容器上下文對象之后,保存在了核心控制器的webApplicationContext屬性(此屬性在父類FrameworkServlet聲明)中,以備處理請求時使用。

    進一步,我們不妨來看看具體構(gòu)造SpringMVC容器上下文的代碼:initWebApplicationContext()會調(diào)到方法createWebApplicationContext(ApplicationContext parent)來完成:

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		Class<?> contextClass = getContextClass();
		//獲取SpringMVC容器的類名XmlWebApplicationContext.class
		//......
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);//使用反射創(chuàng)建SpringMVC容器對象,其實就是這個類org.springframework.web.context.support.XmlWebApplicationContext的對象
		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);
		wac.setConfigLocation(getContextConfigLocation());
		//把init()中設(shè)置的DispatcherServlet的contextConfigLocation屬性(保存著SpringMVC核心配置文件的位置)交給SpringMVC容器,所以以后運行過程中SpringMVC能夠使用springmvc.xml中所有的配置也就不足為奇了。
		configureAndRefreshWebApplicationContext(wac);
		//在這個方法中,掃描所有納入spring管理的類,并且實例化保存到容器中(beanFactory屬性中),以備后用。
		return wac;
         }

    

    最后,我們來看一下createWebApplicationContext(ApplicationContext parent)方法時如何掃描所有納入spring管理的類,并且實例化保存到容器中(beanFactory屬性中)的。其它方法的調(diào)用我不多說了,其中調(diào)到了ComponentScanBeanDefinitionParser類的parse(Element element, ParserContext parserContext)方法,如下:

public BeanDefinition parse(Element element, ParserContext parserContext) {
		String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
		basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
		String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
		// Actually scan for bean definitions and register them.
		ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
		Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);//掃描核心配置文件中<context:component-scan base-package=""/>指定的包,得到所有需要創(chuàng)建的Bean信息
		registerComponents(parserContext.getReaderContext(), beanDefinitions, element);//實例化Bean并且在SpringMVC容器的beanFactory屬性中進行注冊
		return null;
	}

    至此,SpringMVC在服務(wù)器啟動時所做的最主要的三個初始化處理已經(jīng)完成,在后期在接收到HTTP請求時就可以及時高效的進行處理。當然,初始化要做的遠不止這些,只要是配置文件和注解中涉及到的信息基本上都會在服務(wù)器啟動時做初始化處理,比如視圖解析器等等,限于篇幅原因,不再贅述。

看完上述內(nèi)容,你們掌握如何進行SpringMVC源碼中的初始化源碼的方法了嗎?如果還想學到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI