spring 没有web.xmll 怎么初始化spring

博客分类:
一般的Web项目都会在web.xml中加入Spring监听器,内容如下:
&listener&
&listener-class&org.springframework.web.context.ContextLoaderListener&/listener-class&
&/listener&
&context-param&
&param-name&contextConfigLocation&/param-name&
&param-value&classpath*:applicationContext-struts.xml,classpath*:spring/applicationContext.xml&/param-value&
&/context-param&
我们的问题是,Spring是何时以及如何加载我们的配置文件来初始化Bean工厂的,带着这些问题,我们展开研究:
我们先来看看web.xml中配置的监听器的类,来回答我们的问题,Spring是何时来加载我们的配置文件的:
org.springframework.web.context.ContextLoaderListener
它继承了javax.servlet.ServletContextListener接口。
ServletContextListener是J2EE Servlet API中的一个标准接口,
它能够监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期。
当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件,该事件由ServletContextListener来处理。
这里面有两个方法我们比较感兴趣:
* Create the ContextLoader to use. Can be overridden in subclasses.
* @return the new ContextLoader
protected ContextLoader createContextLoader() {
return new ContextLoader();
}
这个方法构造一个默认的ContextLoader,ContextLoader可以理解为Spring上下文的加载器。之所以这样去定义这样一个类,是为了开发人员进行重写此方法来使用一个自定义的Spring上下文的加载器。
* Initialize the root web application context.
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
这个方法很简单,仅仅只是调用了createContextLoader()构造了ContextLoader,并调用其初始化方法。
由此,我们可以得出结论,Spring是在Web项目启动时,通过ServletContextListener机制,来加载以及初始化Spring上下文的。
下面,我们好好研究一下Spring是如何加载其上下文的:
我们先定位ContextLoader类。
看看此类的initWebApplicationContext()方法(省略了不重要的语句)
* Initialize Spring's web application context for the given servlet context,
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* @param servletContext current servlet context
* @return the new WebApplicationContext
* @throws IllegalStateException if there is already a root application context present
* @throws BeansException if the context failed to initialize
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
throws IllegalStateException, BeansException {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
// Determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
this.context = createWebApplicationContext(servletContext, parent);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);
return this.
} catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
} catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
}
其中的有两句比较重要,我们来看看:
ApplicationContext parent = loadParentContext(servletContext);
这个方法的用途主要是用来解决Spring共享环境的,即,如果我们有多个WAR包部署在同一个服务器上,而且这些WAR都共享某一套业务逻辑层。如何共享一套业务逻辑包配置而不要每个WAR都单独配置,这时我们就可能需要Spring的共享环境了。
protected ApplicationContext loadParentContext(ServletContext servletContext) throws BeansException {
ApplicationContext parentContext =
// 从web.xml中读取父工厂的配置文件,默认为:"classpath*:beanRefContext.xml"
String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);
// 从web.xml中读取父类工厂的名称
String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);
if (parentContextKey != null) {
// locatorFactorySelector may be null, indicating the default "classpath*:beanRefContext.xml"
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
this.parentContextRef = locator.useBeanFactory(parentContextKey);
parentContext = (ApplicationContext) this.parentContextRef.getFactory();
return parentC
}
现在我们引入BeanFactoryLocator,它是Spring配置文件的一个定位器,Spring官方给它的定义是用来查找,使用和释放一个BeanFactory或其子类的接口。下面我们看看此图:
ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
是根据参数locatorFactorySelector去一个单例工厂中去拿一个对应的BeanFactoryLocator,也即,如果工厂中没有对应于locatorFactorySelector的BeanFactoryLocator对象,那就返回一个新的BeanFactoryLocator实例(这里是ContextSingletonBeanFactoryLocator的实例),否则,就从工厂里取现有的BeanFactoryLocator对象。
ContextSingletonBeanFactoryLocator里维护了一个静态的Map对象instances,每次需要新增BeanFactoryLocator实例时都会更新这个Map对象,这个Map对象是以配置文件名为KEY,BeanFactoryLocator对象为值。原因很简单,就是希望同一个配置文件只被初始化一次。
如果没有在web.xml中定义locatorFactorySelector这个参数,父环境的配置文件默认使用:"classpath*:beanRefContext.xml"
this.parentContextRef = locator.useBeanFactory(parentContextKey);
此方法定义在SingletonBeanFactoryLocator类中,同样是一个单例工厂模式,判断传入的参数parentContextKey对应的BeanFactory是否有被初始化,经过上面的ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector)指定Spring父环境配置文件,这个方法判断指定的父环境是否被初始化,如果有则返回,没有就进行初始化。看看此方法的实现:
public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
synchronized (this.bfgInstancesByKey) {
BeanFactoryGroup bfg = (BeanFactoryGroup) this.bfgInstancesByKey.get(this.resourceLocation);
if (bfg != null) {
bfg.refCount++;
// Create the BeanFactory but don't initialize it.
BeanFactory groupContext = createDefinition(this.resourceLocation, factoryKey);
// Record its existence now, before instantiating any singletons.
bfg = new BeanFactoryGroup();
bfg.definition = groupC
bfg.refCount = 1;
this.bfgInstancesByKey.put(this.resourceLocation, bfg);
this.bfgInstancesByObj.put(groupContext, bfg);
// Now initialize the BeanFactory. This may cause a re-entrant invocation
// of this method, but since we've already added the BeanFactory to our
// mappings, the next time it will be found and simply have its
// reference count incremented.
initializeDefinition(groupContext);
} catch (BeansException ex) {
this.bfgInstancesByKey.remove(this.resourceLocation);
this.bfgInstancesByObj.remove(groupContext);
throw new BootstrapException("Unable to initialize group definition. " +
"Group resource name [" + this.resourceLocation + "], factory key [" + factoryKey + "]", ex);
BeanFactory beanFactory =
if (factoryKey != null) {
beanFactory = (BeanFactory) bfg.definition.getBean(factoryKey, BeanFactory.class);
} else if (bfg.definition instanceof ListableBeanFactory) {
beanFactory = (BeanFactory) BeanFactoryUtils.beanOfType((ListableBeanFactory) bfg.definition, BeanFactory.class);
throw new IllegalStateException(
"Factory key is null, and underlying factory is not a ListableBeanFactory: " + bfg.definition);
return new CountingBeanFactoryReference(beanFactory, bfg.definition);
} catch (BeansException ex) {
throw new BootstrapException("Unable to return specified BeanFactory instance: factory key [" +
factoryKey + "], from group with resource name [" + this.resourceLocation + "]", ex);
}
此方法分为两作了两件事,
第一,初始化上下文,主意这里初始化的是从web.xml配置参数里的Spring配置文件,也是上面讲loadParentContext方法里的
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
这句指定的参数。这里初始化的是这个配置文件所有Bean。我们指定的factoryKey对应的Bean也是其中之一。
第二,从已经初始化的Spring上下文环境中获取Spring父环境。
&bean id="factoryBeanId" class="org.springframework.context.support.ClassPathXmlApplicationContext"&
&constructor-arg&
&value&sharebean.xml&/value&
&/constructor-arg&
&bean id="factoryBeanId2" class="org.springframework.context.support.ClassPathXmlApplicationContext"&
&constructor-arg&
&value&sharebean2.xml&/value&
&/constructor-arg&
&!—========================= web.xml ========================= --&
&context-param&
&param-name&locatorFactorySelector&/param-name&
&param-value&beanRefFactory.xml&/param-value&
&/context-param&
&context-param&
&param-name&parentContextKey&/param-name&
&param-value&factoryBeanId&/param-value&
&/context-param&
这个一个典型的构造父环境的配置,web项目在启动的时候就会发现里面有Spring父环境的配置,那么Spring首先就会生成一个对应的配置文件为beanRefFactory.xml的BeanFactory(web.xml中的locatorFactorySelector参数指定),同时Spring在解析的时候,会发现factoryBeanId的配置同样为BeanFacotry(beanRefFactory.xml中factoryBeanId对应的Bean),所以Spring在拿父环境时就会写成:
beanFactory = (BeanFactory) bfg.definition.getBean(factoryKey, BeanFactory.class);
方法实现里引入了BeanFactoryGroup类。类的结构很简单
refCount:用来记录实例被外部引用的记数,当调用locator.useBeanFactory(parentContextKey)方法时,引用数就会加1,当调用CountingBeanFactoryReference#release方法时,引用数就会减1,当它变成0时,Spring就会释放掉它占用的内存,同时也会销毁掉它definition变量引用的BeanFactory。下次再调用locator.useBeanFactory(parentContextKey)就会重新初始化BeanFactory。说到release,请同学们参考ContextLoader中如下的两条语句:
// 在调用CountingBeanFactoryReference#release后,即使对象已经销毁,这个Map仍然可以返回locator对象。
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
// 如果对象已经销毁,再调用此方法会再一次初始化BeanFactory
this.parentContextRef = locator.useBeanFactory(parentContextKey);
bfgInstancesByKey:一个Map对象,以配置文件名为Key,配置文件解析后生成的BeanFactory构成的BeanFactoryGroup为值。
bfgInstancesByObj:一个Map对象,以BeanFactoryGroup.definitiion为Key,以BeanFactoryGroup为值。这个对象主要还是在CountingBeanFactoryReference#release时使用。
下面,我看再看看另一个地方:
if (parentContextKey != null) {
// locatorFactorySelector may be null, indicating the default "classpath*:beanRefContext.xml"
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
this.parentContextRef = locator.useBeanFactory(parentContextKey);
parentContext = (ApplicationContext) this.parentContextRef.getFactory();
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
上面这句仅仅是做了如下工作:
BeanFactoryLocator bfl = (BeanFactoryLocator) instances.get(resourceLocation);
if (bfl == null) {
// 仅仅只是设置了ContextSingletonBeanFactoryLocator里的resourceLocation属性的值,并没有初始化工厂。
bfl = new ContextSingletonBeanFactoryLocator(resourceLocation);
instances.put(resourceLocation, bfl);
}
而我们使用工厂模式的时候,一般是把对象初始化好了,再给外部使用,为什么Spring这里要多此一举,在调用getInstance这后还要去调用useBeanFactory来初始化父环境?为什么Spring开发者不写成如下:
BeanFactoryLocator bfl = (BeanFactoryLocator) instances.get(resourceLocation);
if (bfl == null) {
bfl = new ContextSingletonBeanFactoryLocator(resourceLocation);
// 下面这句可能换成 initBeanFactory 类似语句,这里只是打个比方
bfl.useBeanFactory(parentContextKey);
instances.put(resourceLocation, bfl);
}
本来我认为这个写法是必须的,后来想想也不是,不过这里体现了Spring的灵活设计。如果按排上面的方法进行改造有几点不妥,1,每次都会初始化,开销比较大,可能有需求是需要延迟初始化的。2,每次都需要初始化都需要传入两个参数,分别为:配置文件名与父工厂名,3,类职责混乱,比如一个配置文件中可能定义了多个父环境的Bean,采用Spring这种方法是很清晰的:
// 返回BeanFactoryLocator方便定位某个配置文件。
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(“classpath*: parentBeanFactory.xml”);
parentContextRef1 = locator.useBeanFactory("parent1Key");
parentContextRef2 = locator.useBeanFactory("parent2Key");
而使用我们改造的方法,则要写成如下:
parentContextRef1 = ContextSingletonBeanFactoryLocator.getInstance("parentBeanFactory.xml", "parent1Key");
parentContextRef2 = ContextSingletonBeanFactoryLocator.getInstance("parentBeanFactory.xml", "parent2Key");
相当麻烦且无语,引用了也只是这个配置文件中的某一个Bean的引用,没什么意义。
这就是为什么BeanFactoryLocator接口存在的一个原因,用于查找某个配置文件中的一个BeanFactory。
public interface BeanFactoryLocator {
BeanFactoryReference useBeanFactory(String factoryKey) throws BeansE
this.context = createWebApplicationContext(servletContext, parent);
我们来看看这个函数做了些什么:
protected WebApplicationContext createWebApplicationContext(
ServletContext servletContext, ApplicationContext parent) throws BeansException {
// 获得需要实例化的CONTEXT类名,确定ContextClass的类型。如果在web.xml中配置了contextClass这个parameter,
// 使用这个指定的类作为ContextClass,会抛出ClassNotFound的异常。反之,使用默认的XmlWebApplicationContext
Class contextClass = determineContextClass(servletContext);
// 所有的WebApplicationContext必须实现ConfigurableWebApplicationContext接口
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
// 设置父环境
wac.setParent(parent);
// 设置Servlet上下文环境
wac.setServletContext(servletContext);
// 设置Spring配置文件路径
wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));
customizeContext(servletContext, wac);
wac.refresh();
protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException {
// 获得需要实例化的CONTEXT类名,在web.xml中有设置,如果没有设置,那么为空
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
return ClassUtils.forName(contextClassName);
} catch (ClassNotFoundException ex) {
throw new ApplicationContextException("Failed to load custom context class.", ex);
//如果在spring web.xml中没有设置context类位置,那么取得默认context
//取得defaultStrategies配置文件中的WebApplicationContext属性
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
} catch (ClassNotFoundException ex) {
throw new ApplicationContextException("Failed to load default context class.", ex);
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
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
再来看看Spring是如果进行初始化ApplicationContext的。就以XmlWebApplicationContext来说,它继承了ConfigurableWebApplicationContext这个接口,里面有个refresh()方法,我们可以看看它的实现(AbstractApplicationContext):
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
beanFactory.destroySingletons();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
}
这个方法的实现由于涉及的东西比较多,比较国际化,事件等等,等我们理解了后续的源代码分析之后再重新过来进行研究。这样效率更高点。
这样关于Spring在web项目中加载及初始化的方式我们大概也了解的比较清楚了,我们可以看到,Spring就第一步,加载都已经做了很多工作,不得不佩服Spring团队的智慧。
最后,Spring加载完成之前,会将ApplicationContext放入ServletContext中,方便程序进行访问。
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);
其中WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE定义如下:
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
Spring环境
加载组件:ContextLoaderListener
配置路径:Servlet环境初始化参数contextConfigLocation指定的路径
缺省路径: 没有缺省路径
Spring环境的父环境
加载组件:ContextLoaderListener和ContextSingletonBeanFactoryLocator
配置路径:Servlet环境初始化参数locatorFactorySelector指定Bean工厂定位器使用的给BeanFactory,Servlet环境初始化参数parentContextKey指定Bean工厂定位器用于查找BeanFactory的关键字
缺省路径: parentContextKey的缺省路径是classpath*:beanRefFactory.xml
这里我们还有一个功能相近的类没有进行说明:
ContextJndiBeanFactoryLocator
有兴趣的同学可以自己看一下。
转自:/bobzeng/articles/1877140.html
浏览: 87576 次
来自: 北京
fsdfdsfdsfdsdfsfdsfsddfsfds
String [] idArr = {&tom&qu ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'Spring源码探究:IoC容器在Web容器中的创建及初始化 - 简书
Spring源码探究:IoC容器在Web容器中的创建及初始化
关于IoC容器和控制反转(也被称为依赖注入)模式以及Spring IoC的应用场景我在这里就不进行赘述了,下面直接深入到Spring的源码当中来探究一下IoC容器究竟是如何工作的。
在文章开头,我们要明确两个概念:
IoC容器的创建就是我们创建一个容器,使其拥有IoC容器的基本结构;(下文中提到的的createWebApplicationContext完成的是IoC容器的创建工作)
在完成IoC容器创建的前提下进行bean的注册以及依赖注入之后才算完成了IoC容器的初始化(下文中提到的ConfigureAndRefreshWebApplicationContext进行的是IoC容器的初始化工作但是关于容器初始化的细节我将放到后面的博客进行介绍)。
在Spring IoC容器系列的设计中,我们可以看到两个两个主要的容器系列:一个是实现BeanFactory接口的简单容器系列,这个系列容器只实现了容器的最基本功能;另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配。有了这两种基本的容器系列,基本上可以满足用户对IoC容器使用的大部分需求了。下面我们主要来看看IoC容器在Web容器中是如何进行初始化的。
既然我们要探究IoC容器初始化的过程,那就要问一个问题:IoC容器什么时候会进行初始化的行为呢?
我们先来看一个非常基础的场景:
web.xml配置文件中的一部分
上面是web.xml配置文件中的一部分
contextConfigLocation对应的value是Spring配置文件的绝对路径;
下面这个监听器主要用来对Servlet容器(在这里指的是Tomcat)的行为进行监听
我们先来看看监听器类ContextLoaderListener中有什么东西:
ContextLoaderListener源码
我们可以发现ContextLoaderListener继承自ContextLoader,并且还实现了ServletContextListener。并且它的构造函数中传入了一个WebApplicationContext,它是继承自ApplicationContext接口的高级IoC容器。
ServletContextListener源码
ServletContextListener是Servlet中比较重要的一个接口:它的作用是用来监听Servlet容器的启动和销毁事件。所以在ContextLoaderListener中:
contextInitialized方法的入参或是监听的Event是ServletContextEvent事件,也就是Tomcat启动加载完web.xml会产生的事件,ServletContextEvent持有了从web.xml加载的初始化配置的ServletContext上下文。
ContextDestroyed方法的入参或是监听的Event是ServletContextEvent事件,在Tomcat关闭的时候执行该方法。
所以我们现在可以先捋一下流程:当Servlet容器启动事件发生时,将被ContextLoaderListen监听器监听到。此时ContextLoaderListener会调用实现ServletContextListener接口后实现的contextInitialized方法,并把在web.xml加载初始化后获取的ServletContext传入initWebApplicationContext函数中进行IoC容器的初始化。
因为initWebApplicationContext函数是从ContextLoader继承过来的,所以我们现在进入ContextLoader源码中看一看。
ContextLoader类中的静态代码块
映入眼帘的是个静态代码块:
创建一个ClassPathResource对象,同时把值为"ContextLoader.properties"的一个常量作为参数传入。易知ContextLoader.properties文件与ContextLoader类是在同一个目录下的;ContextLoader.properties文件内容如下:org.springframework.web.context.WebApplicationContext=
org.springframework.web.context.support.XmlWebApplicationContext
因此我们可以得知Spring默认初始化的是XmlWebApplicationContext容器
得到一个Properties对象,后面讲根据类名来创建对应的ApplicationContext容器
下面来看看initiWebApplicationContext方法
initWebApplicationContext方法源码
我们现在可以接着刚才的流程继续讲下去:当调用ContextLoaderListener中的initWebApplicationContext的函数并且将获取到的servletContext作为参数传入之后,initWebApplicationContext首先会尝试从servletContext中获取根容器,如果容器不为空,则容器初始化失败---因为web.xml中可能定义了多个IoC容器的加载器。假如此时容器还未初始化,则调用createWebApplicationContext方法来创建一个容器。创建完容器之后,将会调用一个非常重要的configureAndRefreshWebApplicationContext方法。在执行这个方法的时候,会将从ApplicationContext.xml配置文件中获取到的内容配置到已经创建好了的XmlWebApplicationContext容器中去,并调用refresh方法来完成容器的初始化。然后,再将已经完成初始化的XmlWebApplicationContext容器注册到servletContext中去。
其实在Web容器中,ServletContext为Spring的IoC容器提供了宿主环境,对应的建立起一个IoC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象、数据存取对象、资源、事务管理器等各种中间层对象。在这个上下文的基础上,与Web MVC相关还会有一个上下文来保持控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。因为在initWebApplicationContext方法中我们可以看到其实创建ApplicationContext容器的工作是交由createWebApplicationContext方法来实现的,下面我们来看看这个方法:
createWebApplicationContext函数源码
createWebApplicationContext函数功能:
决定要创建的ApplicationContext类型;
实例化一个ApplicationContext
那么它是如何决定要创建的ApplicationContext类型的呢?起作用的其实是方法中第一行的determineContextClass方法
determineContextClass方法源码
完成了IoC容器的创建之后,在initWebApplicationContext中讲调用configureAndRefreshWebApplicationContext来对该IoC进行初始化:
为创建好的IoC容器设置Web应用的上下文,以便二者整合;
为同一个IoC容器设置配置文件的绝对路径;
调用IoC容器的refresh函数对其进行初始化
configureAndRefreshWebApplicationContext函数
由于IoC容器的初始化涉及到比较多的步骤:包括BeanDefinition的Resource定位等等,所以我将在后面另开博客进行介绍。
Github::/eakonzhao

我要回帖

更多关于 spring boot web.xml 的文章

 

随机推荐