前文回顾
上篇 探索SpringBoot-一起看看Spring核心源码之BeanFactory(七)介绍了几个概念。
BeanFactory接口定义了Ioc容器最基本的方法。DefaultListableBeanFactory是实现BeanFactory基本功能的实现类。
ApplicationContext
但是,小伙伴们。我们一般使用的更多是ApplicationContext,而不是使用仅仅实现了BeanFactory的实现类。那么ApplicationContext和BeanFactory之间的区别和联系是什么呢?
/** * Central interface to provide configuration for an
application. * This is read-only while the application is running, but
may be * reloaded if the implementation supports this. * * <p>An ApplicationContext provides: * <ul> * <li>Bean factory methods for accessing application
components. * Inherited from {@link
org.springframework.beans.factory.ListableBeanFactory}. * <li>The ability to load file resources in a generic
fashion. * Inherited from the {@link
org.springframework.core.io.ResourceLoader} interface. * <li>The ability to publish events to registered
listeners. * Inherited from the {@link ApplicationEventPublisher}
interface. * <li>The ability to resolve messages, supporting
internationalization. * Inherited from the {@link MessageSource} interface. * <li>Inheritance from a parent context. Definitions in a
descendant context * will always take priority. This means, for example, that
a single parent * context can be used by an entire web application, while
each servlet has * its own child context that is independent of that of any
other servlet. * </ul> * * <p>In addition to standard {@link
org.springframework.beans.factory.BeanFactory} * lifecycle capabilities, ApplicationContext
implementations detect and invoke * {@link ApplicationContextAware} beans as well as {@link
ResourceLoaderAware}, * {@link ApplicationEventPublisherAware} and {@link
MessageSourceAware} beans. *
定义是对一个应用提供配置的核心接口。
下面又讲到了ApplicationContext提供的几个能力。
- 拥有
BeanFactory访问基本容器组件的能力 - 加载文件的能力,继承了
ResourceLoader和Resource - 发布事件到注册的监听器的能力,继承了接口
ApplicationEventPublisher - 处理消息,支持国际化的能力,可以看到继承了
MessageSource接口
看下面的类继承图,可以更加清晰看到不同类之间的继承关系

所以,ApplicationContext比BeanFactory拥有更多,更强大的功能。ApplicationContext是一中更加高级的容器。一般在开发应用的过程中,一般都使用ApplicationContext作为基本的IoC容器。然后,我们再来看一下ClassPathXmlApplicationContext的具体实现。
ClassPathXmlApplicationContext
废话不多说,直接上源码。可以看到基本上在ClassPathXmlApplicationContext只做了三件事情。
- 写了一个构造函数
ClassPathXmlApplicationContext(String[],Boolean,ApplicationContext), - 写了另外一个构造函数
ClassPathXmlApplicationContext(String,Class,ApplicationContext)的构造函数。 - 写了
getConfigResources的接口,而且是protected的,估计是设计为了之后继承的子类使用的。
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
private Resource[] configResources;
..................................................................
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
public ClassPathXmlApplicationContext(String path, Class clazz) throws BeansException {
this(new String[] {path}, clazz);
}
...................................................
public ClassPathXmlApplicationContext(String[] paths, Class clazz, ApplicationContext parent)
throws BeansException {
super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for (int i = 0; i < paths.length; i++) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
refresh();
}
@Override
protected Resource[] getConfigResources() {
return this.configResources;
}
}
所以,其实关于ClassPathXmlApplicationContext类里面的实现逻辑其实是非常少而且简单的。另外,我们也应该注意到在构造函数中最后都会使用到refresh函数。其实这个refresh过程会牵涉Ioc容器启动的一系列复杂的过程,而且对于不同的容器实现,这个过程都是相似的,因为实在抽象的基类里面实现的。
结合我们在
探索SpringBoot-一起来看看Spring容器加载核心源码(六)中提到的refresh源代码,我们可以看到该函数大致会有以下三个步骤。
- BeanDefinition的Resource定位
- 载入
- 注册
《Spring技术内幕》中也提到了
Spring把这三个过程分开,并使用不同的模块来完成,如使用想要的ResourceLoader、BeanDefinitionReader等模块,通过这样的设计方式,可以让用户更加灵活地对三个过程进行剪裁或扩展,定义出最适合自己的IoC容器的初始化过程。
下篇逐个分析初始化的三个过程。
关于
以后这里每天都会写一篇文章,题材不限,内容不限,字数不限。尽量把自己每天的思考都放入其中。
如果这篇文章给你带来了帮助,能请你写下是哪个部分吗?有效的反馈是对我最大的帮助。
我是shane。今天是2019年8月13日。百天写作计划的第二十天,20/100。