您好,登錄后才能下訂單哦!
如何進行SpringMVC源碼中的初始化源碼,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
所有Java的MVC框架都是基于servlet的,SpringMVC也不例外。它提供核心控制器DispatcherServlet,并且在此Servlet實例化后做出一系列的初始化處理,從而保證后期的高效率運行。在研究源碼之前,我們首先看一下DispatcherServlet的繼承結構。這三個Servlet類是SpringMVC的核心控制器類,各負其職來完成SpringMVC的各項功能。
其中,HttpServletBean主要做一些初始化的工作,將web.xml中配置的參數設置到核心控制器Servlet中,比如servlet標簽的初始化參數子標簽init-param標簽中配置的參數;
FrameworkServlet將Servlet與Spring容器上下文關聯。其實也就是初始化FrameworkServlet的屬性webApplicationContext,這個屬性代表SpringMVC上下文,其實也就是spring技術中web.xml配置的ContextLoaderListener監聽器初始化的容器上下文,所以我們也說SpringMVC是基于Spring的;
DispatcherServlet完成SpringMVC對web請求各個功能的實現。比如請求映射處理、視圖處理、異常處理等。
任何web功能的實現都是從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核心處理器,并且傳遞了參數contextConfigLocation以指定SpringMVC核心配置文件的位置,在服務器啟動時進行加載并實例化。
HttpServletBean覆蓋了init()方法,所有初始化處理都是此Servlet實例化之后于init方法中完成的,下面我們就來看看其中三個最主要信息的初始化:讀取初始化參數contextConfigLocation、構造SpringMVC容器、創建所有的Bean對象。
public final void init() throws ServletException { //...... PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);//從ServletConfig中獲取初始化參數(如contextConfigLocation=classpath:springmvc.xml等) if (!pvs.isEmpty()) { try { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);//構造BeanWrapper對象,接下來就是由BeanWrapper完成初始化處理 ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); bw.setPropertyValues(pvs, true);//把初始化參數contextConfigLocation設置到核心控制器DispatcherServlet的contextConfigLocation屬性中. } catch (BeansException ex) { //... } } initServletBean();//這個方法在本類中是空實現,它用來是被子類(FrameworkServlet)覆蓋的,在子類中進行構造SpringMVC容器上下文對象,這也是模板設計模式的具體應用。 //...... }
下面先來看BeanWrapper是如何設置初始化參數的:從源碼我們會看到,BeanWrapper是個接口,實現類是BeanWrapperImpl,BeanWrapperImpl是AbstractNestablePropertyAccessor的子類,AbstractNestablePropertyAccessor有個屬性wrappedObject,保存了核心控制器的引用,那么BeanWrapperImpl類也具有對DispatcherServlet對象的引用。在BeanWrapperImpl中有一個方法setValue()用來保存初始化參數到DispatcherServlet的屬性中:
setValue(final Object object, Object valueToApply) //...... if (System.getSecurityManager() != null) { //...... } else { writeMethod.invoke(getWrappedInstance(), value);//這里使用反射把獲取到的初始化參數contextConfigLocation核心控制器的屬性contextConfigLocation。 } //...... }
其實,SpringMVC本身能用到的初始化參數也就是contextConfigLocation了。
接下來我們來看看FrameworkServlet類的initServletBean()方法如何構造SpringMVC容器上下文對象:FrameworkServlet是HttpServletBean的子類,它覆蓋了initServletBean()方法,主要用來在服務器啟動時構造SpringMVC容器上下文對象。
protected final void initServletBean() throws ServletException { //...... try { this.webApplicationContext = initWebApplicationContext();//創建出SpringMVC容器對象 initFrameworkServlet(); } //...... }
很顯然,調用initWebApplicationContext()方法創建出SpringMVC容器上下文對象之后,保存在了核心控制器的webApplicationContext屬性(此屬性在父類FrameworkServlet聲明)中,以備處理請求時使用。
進一步,我們不妨來看看具體構造SpringMVC容器上下文的代碼:initWebApplicationContext()會調到方法createWebApplicationContext(ApplicationContext parent)來完成:
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { Class<?> contextClass = getContextClass(); //獲取SpringMVC容器的類名XmlWebApplicationContext.class //...... ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);//使用反射創建SpringMVC容器對象,其實就是這個類org.springframework.web.context.support.XmlWebApplicationContext的對象 wac.setEnvironment(getEnvironment()); wac.setParent(parent); wac.setConfigLocation(getContextConfigLocation()); //把init()中設置的DispatcherServlet的contextConfigLocation屬性(保存著SpringMVC核心配置文件的位置)交給SpringMVC容器,所以以后運行過程中SpringMVC能夠使用springmvc.xml中所有的配置也就不足為奇了。 configureAndRefreshWebApplicationContext(wac); //在這個方法中,掃描所有納入spring管理的類,并且實例化保存到容器中(beanFactory屬性中),以備后用。 return wac; }
最后,我們來看一下createWebApplicationContext(ApplicationContext parent)方法時如何掃描所有納入spring管理的類,并且實例化保存到容器中(beanFactory屬性中)的。其它方法的調用我不多說了,其中調到了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=""/>指定的包,得到所有需要創建的Bean信息 registerComponents(parserContext.getReaderContext(), beanDefinitions, element);//實例化Bean并且在SpringMVC容器的beanFactory屬性中進行注冊 return null; }
至此,SpringMVC在服務器啟動時所做的最主要的三個初始化處理已經完成,在后期在接收到HTTP請求時就可以及時高效的進行處理。當然,初始化要做的遠不止這些,只要是配置文件和注解中涉及到的信息基本上都會在服務器啟動時做初始化處理,比如視圖解析器等等,限于篇幅原因,不再贅述。
看完上述內容,你們掌握如何進行SpringMVC源碼中的初始化源碼的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。