Spring MVC 上下文(ApplicationContext)初始化入口

Spring MVC 上下文(ApplicationContext)初始化入口

Spring MVC 上下文(ApplicationContext)初始化入口

Spring 常用上下文容器有哪些

ApplicationContext

  1. ClassPathXmlApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml");
  1. AnnotationConfigApplicationContext
AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

應該來說是很少使用這種方法用於生產開發,常常在學習Spring做demo的時候會使用到。更有可能出現在Spring項目的代碼測試,不過呢,單元測試的框架(比如 JUnit)已經提供了簡單的方式,也就不建議直接實例化上下文。因為實例化一個上下文還得要做維護,再者現在常用的是基於Web的開發,也就是常用 Spring MVC。如果沒有基於 Web 應用的開發,那麼很可能就是一個小的程序,類似於提供給第三方使用的 SDK 代碼,那麼使用 Spring 感覺會太重,最重要是自己要維護一個 ApplicationContext,感覺不是那麼方便

Web ApplicationContext

以下兩個是針對 Spring MVC 的應用上下文。WebApplicationContext 實例會在應用啟動之後由Spring實例化並維護,而平常在學習的時候也往往不會自己去實例化 WebApplicationContext 對象,因為將因為部署到web容器(比如 tomcat),啟動之後就可以直接測試了。單元測試有專門的框架處理(比如 JUnit),可以很簡單的實現測試。web項目的開發關鍵點在於讓web容器初始化之後提醒Spring ApplicationContext 初始化,例如 tomcat 的 ServletContext 會維護一個 WebApplicationContext。

  1. XmlWebApplicationContext
@Test
public void handlerBeanNotFound() throws Exception {
MockServletContext sc = new MockServletContext("");
XmlWebApplicationContext root = new XmlWebApplicationContext();
root.setServletContext(sc);
root.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map1.xml"});
root.refresh();
XmlWebApplicationContext wac = new XmlWebApplicationContext();
wac.setParent(root);
wac.setServletContext(sc);
wac.setNamespace("map2err");
wac.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map2err.xml"});
try {
wac.refresh();
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (FatalBeanException ex) {
NoSuchBeanDefinitionException nestedEx = (NoSuchBeanDefinitionException) ex.getCause();
assertEquals("mainControlle", nestedEx.getBeanName());
}
}
  1. AnnotationConfigWebApplicationContext:沒找到合適的示例代碼

ApplicationContext 入口

這種方式需要自己維護 ApplicationContext 實例,也就是開發使用的時候 new ApplicationContext,入口自己控制

WebApplicationContext 入口

web.xml 配置和 全註解 配置啟動會有一些差別。

web.xml 配置

web.xml 中關於Spring的配置項,也非常常見。


xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">


contextConfigLocation

classpath:applicationContext.xml




org.springframework.web.context.ContextLoaderListener




dispatcher
org.springframework.web.servlet.DispatcherServlet

contextConfigLocation
classpath:applicationContext-mvc.xml

1


dispatcher
/


WebApplicationContext 的初始化調用鏈路:ContextLoaderListener.contextInitialized-->ContextLoader.initWebApplicationContext-->ContextLoader.createWebApplicationContext-->ContextLoader.determineContextClass-->ContextLoader.determineContextClass。

determineContextClass 源碼如下:

protected Class> determineContextClass(ServletContext servletContext) {
// 自定義的 ApplicationContext

String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
// 缺省為 XmlWebApplicationContext
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}

默認 WebApplicationContext

根據上面的 web.xml 配置是沒有指定 ApplicationContext 的實現的,所以會執行:contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());。defaultStrategies 的實現如下:

/**
* Name of the class path resource (relative to the ContextLoader class)
* that defines ContextLoader's default strategy names.
*/
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
private static final Properties defaultStrategies;
static {
// 讀取文件 ContextLoader.properties 中的配置
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
}
}

根據 ContextLoader.properties 中的配置完成,裡邊的內容如下:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

所以呢,通過 web.xml 配置Spring MVC默認的上下文是: XmlWebApplicationContext

指定 WebApplicationContext

如果在 web.xml 中配置 contextClass 屬性,例如下面的方式,摘自 StackOverflow:How to register Spring @Configuration annotated class instead of applicationContext.xml file in web.xml?




contextClass

org.springframework.web.context.support.AnnotationConfigWebApplicationContext




contextConfigLocation
com.acme.AppConfig



org.springframework.web.context.ContextLoaderListener



dispatcher
org.springframework.web.servlet.DispatcherServlet


contextClass

org.springframework.web.context.support.AnnotationConfigWebApplicationContext




contextConfigLocation
com.acme.web.MvcConfig




dispatcher
/app/*


感覺很神奇,但是也很麻煩的樣子。我是不建議混合 web.xml 配置啟動和全註解啟動,亂且不好看懂。

全註解配置

全註解方式一般是實現WebApplicationInitializer或者通過繼承AbstractAnnotationConfigDispatcherServletInitializer。AbstractAnnotationConfigDispatcherServletInitializer 是WebApplicationInitializer的實現類。想知道全註解配置下tomcat如何Spring IOC怎樣被加載,可以閱讀篇文章Spring揭秘--尋找遺失的web.xml

全註解方式配置常用類似如下的代碼:

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* @author imssbora
*/
public class MyWebAppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer{
@Override
protected Class>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
protected Class>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};

}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}

啟動路徑:SpringServletContainerInitializer.onStartup-->AbstractContextLoaderInitializer.onStartup-->AbstractContextLoaderInitializer.registerContextLoaderListener-->AbstractAnnotationConfigDispatcherServletInitializer.createRootApplicationContext。

createRootApplicationContext 源碼如下:

protected WebApplicationContext createRootApplicationContext() {
Class>[] configClasses = this.getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
rootAppContext.register(configClasses);
return rootAppContext;
} else {
return null;
}
}

可以看出實例化了 AnnotationConfigWebApplicationContext 對象。

加Java架構師進階交流群獲取Java工程化、高性能及分佈式、高性能、深入淺出。高架構。性能調優、Spring,MyBatis,Netty源碼分析和大數據等多個知識點高級進階乾貨的直播免費學習權限 都是大牛帶飛 讓你少走很多的彎路的 群.號是 338549832 對了 小白勿進 最好是有開發經驗

注:加群要求

1、具有工作經驗的,面對目前流行的技術不知從何下手,需要突破技術瓶頸的可以加。

2、在公司待久了,過得很安逸,但跳槽時面試碰壁。需要在短時間內進修、跳槽拿高薪的可以加。

3、如果沒有工作經驗,但基礎非常紮實,對java工作機制,常用設計思想,常用java開發框架掌握熟練的,可以加。

4、覺得自己很牛B,一般需求都能搞定。但是所學的知識點沒有系統化,很難在技術領域繼續突破的可以加。

5.阿里Java高級大牛直播講解知識點,分享知識,多年工作經驗的梳理和總結,帶著大家全面、科學地建立自己的技術體系和技術認知!


分享到:


相關文章: