前言
昨晚做了个梦......,好!上篇Spring IOC 源码调试一的进度进行到ClassPathXmlApplicationContext类构造方法中的
refresh()方法,那这一篇就开始进入到大名鼎鼎的refresh()
方法。
项目结构
这是调试代码
开始调试
1.执行ClassPathXmlApplicationContext
的refresh()
方法
其中会先判断if (refresh)
,这个参数默认是true
,点进new ClassPathXmlApplicationContext(location)
这个代码中的构造方法就可以看到。然后执行refresh()
方法,但是该方法被封装到了父类 AbstractApplicationContext
中。
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable
ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
// 调用父类 AbstractApplicationContext#refresh() 的方法
refresh();
}
}
复制代码
2.执行AbstractApplicationContext
类的refresh()
方法
此时代码进到AbstractApplicationContext
类中,下面是refresh()
总揽,和一些方法注释。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 创建并初始化 BeanFactory 容器(DefaultListableBeanFactory对象),后面很多方法都需要这个参数
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 填充 BeanFactory 功能
// 比如 context的 ClassLoader 和 后置处理器等等。
prepareBeanFactory(beanFactory);
try {
// 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
postProcessBeanFactory(beanFactory);
// 激活各种BeanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截Bean创建的Bean处理器,即注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 初始化上下文中的资源文件,如国际化文件的处理等
initMessageSource();
// 初始化上下文事件广播器
initApplicationEventMulticaster();
//预留给 AbstractApplicationContext 的子类用于初始化其他特殊的 bean,该方法需要在所有单例 bean 初始化之前调用。
onRefresh();
// Check for listener beans and register them.
registerListeners();
// 初始化剩下的单例Bean(非延迟加载的)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
复制代码
2-1.执行AbstractApplicationContext
类的prepareRefresh()
方法
这个方法意思就是准备好应用上下文环境。
protected void prepareRefresh() {
// Switch to active.
// 设置启动日期
this.startupDate = System.currentTimeMillis();
// 设置 context 是否关闭的 状态
this.closed.set(false);
// 设置当前容器激活状态
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
} else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
//初始化context environment(上下文环境)中的占位符属性来源(该方法由子类去实现)
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 对 容器上下文环境 中的属性进行必要的验证
getEnvironment().validateRequiredProperties();
// 实例化一个 LinkedHashSet 存储 预刷新应用的监听器
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
} else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// 允许收集早期的ApplicationEvents,一旦多主机可用就要发布
// todo 什么意思? 作用?
this.earlyApplicationEvents = new LinkedHashSet<>();
}
复制代码
2-2.执行AbstractApplicationContext
类的obtainFreshBeanFactory
方法
在obtainFreshBeanFactory
方法中又调用了refreshBeanFactory()
方法,但是在AbstractApplicationContext
类中该方法是个空方法,并且此时调用refreshBeanFactory()
方法的类依然是ClassPathApplicationContext
对象,所以下一步进入到的ClassPathApplicationContext
的父类AbstractRefreshableApplicationContext
的refreshBeanFactory()
方法中(多跟几遍代码,ClassPathApplicationContext
类的继承关系就会理清楚了)
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化容器核心方法
refreshBeanFactory();
return getBeanFactory();
}
复制代码
2-3. 执行AbstractRefreshableApplicationContext
的refreshBeanFactory()
方法
该方法中重要操作有:
DefaultListableBeanFactory beanFactory = createBeanFactory()
·:创建 BeanFactory 容器对象loadBeanDefinitions(beanFactory)
:加载 BeanDefinition 们,具体提的类实现不同的方法this.beanFactory = beanFactory
:将容器对象赋值给AbstractRefreshableApplicationContext
的private DefaultListableBeanFactory beanFactory
属性
/**
* 该方法是被final修饰 不允许被子类修改
* 该方法是 实例化容器 的重要方法
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 若已有 BeanFactory ,销毁它的 Bean 们,并销毁 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建 BeanFactory 容器对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置 BeanFactory 的序列id
beanFactory.setSerializationId(getId());
// 定制 BeanFactory 设置相关属性
customizeBeanFactory(beanFactory);
// 加载 BeanDefinition 们,具体提的类实现不同的方法
loadBeanDefinitions(beanFactory);
// 加锁防止
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
复制代码
2-4. (重点)执行AbstractRefreshableApplicationContext
的createBeanFactory()
方法创建容器对象
2-4-1.执行DefaultListableBeanFactory
(容器对象)的构造方法
其中new DefaultListableBeanFactory
对象时,还调用了一个getInternalParentBeanFactory()
方法。其中getInternalParentBeanFactory()
方法封装在了AbstractRefreshableApplicationContext
的父类AbstractApplicationContext
中
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
复制代码
2-4-2.getInternalParentBeanFactory()`方法
此时代码逻辑在AbstractApplicationContext
类中。该方法是先获取容器应用上下文下文对象,如果有则传递给DefaultListableBeanFactory
的构造方法。此时获取到的getParent()
为null
,详情请见上篇博客的serParent(parent)
部分
protected BeanFactory getInternalParentBeanFactory() {
return (getParent() instanceof ConfigurableApplicationContext ?
((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent());
}
复制代码
2-4-3.实例化DefaultListableBeanFactory
容器对象
此时进入DefaultListableBeanFactory
构造方法,上一步中getInternalParentBeanFactory()
方法获取到的返回值为null
所以此时BeanFactory parentBeanFactory
值为null
。然后就是层层向上调用父类的构造方法。调用顺序:
DefaultListableBeanFactory
-->AbstractAutowireCapableBeanFactory
-->AbstractBeanFactory
其中执行AbstractAutowireCapableBeanFactory
类构造方法时会有一些逻辑。
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
复制代码
2-4-4.执行AbstractAutowireCapableBeanFactory
类的有参构造方法
下面代码中看到在AbstractAutowireCapableBeanFactory
构造方法中有两个操作
this()
中调用了父类构造方法和执行了三个ignoreDependencyInterface
操作setParentBeanFactory(parentBeanFactory)
此时parentBeanFactory参数为null。这个方法有些双亲委派的思想,而且这个方法具体实现是封装在了AbstractBeanFactory
类中。
2-4-5. 简单说一下ignoreDependencyInterface
方法
ignoreDependencyInterface
的主要功能是忽略给定接口的自动装配功能。
啥意思?就是说你的类实现了被ignoreDependencyInterface()
的接口,不能被自动注入到其他的Bean中。比如A类中有个B类的属性,但是B类实现了被ignoreDependencyInterface()
的接口,此时你在A类中注入B,Spring时不会给你实例化B类的。
2-4-6. 完成DefaultListableBeanFactory
(容器对象)实例化
此时从2-4-1到2-4-6就完成了DefaultListableBeanFactory
对象的实例化,即完成了AbstractRefreshableApplicationContext
的createBeanFactory()
方法--->回到AbstractRefreshableApplicationContext
的refreshBeanFactory()
方法中,下一步执行loadBeanDefinitions(beanFactory)方法
类 :AbstractRefreshableApplicationContext
/**
* 该方法是被final修饰 不允许被子类修改
* 该方法是 实例化容器 的重要方法
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 若已有 BeanFactory ,销毁它的 Bean 们,并销毁 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建 BeanFactory 容器对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置 BeanFactory 的序列id
beanFactory.setSerializationId(getId());
// 定制 BeanFactory 设置相关属性
customizeBeanFactory(beanFactory);
// 加载 BeanDefinition 们,具体提的类实现不同的方法
loadBeanDefinitions(beanFactory);
// 加锁防止
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
复制代码
2-5(重点)执行AbstractXmlApplicationContext
类的loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
该方法是加载/解析Bean元数据信息的方法,此时Spring的容器已经创建好,会把所有的Bean封装成BeanDefiniton
(Bean元数据信息)放入容器中。
该方法也有很多个实现,调试代码用的是ClassPathXmlApplicationContext
类所以具体实现是在AbstractXmlApplicationContext
类中
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建一个 XmlBeanDefinitionReader XML解析器对象 , 需要一个 beanFactory
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 在实例化 AbstractRefreshableConfigApplicationContext 时 就已经设置了 Environment 属性
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 容器应用上下文对象自身 也是 一个 ResourceLoader 类型
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
/**
* 装载 BeanDefinitions 最后调用的 XmlBeanDefinitionReader#loadBeanDefinitions()方法
*/
loadBeanDefinitions(beanDefinitionReader);
}
复制代码
方法中主要操作
new XmlBeanDefinitionReader(beanFactory)
创建一个 XmlBeanDefinitionReader XML解析对象beanDefinitionReader.setEnvironment(this.getEnvironment())
,给解析对象设置运行环境对象,此时this.getEnvironment()
是有返回值的,详情请看上篇博客的``getEnvironment()方法
介绍beanDefinitionReader.setResourceLoader(this)
设置资源加载器,此时的this就是ClassPathXmlApplication
对象,因为到现在代码依然在ClassPathXmlApplication
的构造方法中。因为ClassPathXmlApplication
间接实现了ResourceLoader
接口(Spring统一资源加载器,用来获取资源对象Resource
。这篇博客有详细介绍ResourceLoader
loadBeanDefinitions(beanDefinitionReader)
装载所有BeanDefinitions
(Bean的元数据信息对象)
2-5-1: 执行AbstractXmlApplicationContext
类的loadBeanDefinitions(XmlBeanDefinitionReader reader)
方法
该方法中有两个操作
- 获取
Resource
资源文件,通过getConfigResources()
或getConfigLocations()
方法。其中getConfigLocations()
有返回值的(看[Spring IOC 源码调试一]的setConfigLocations(@Nullable String... locations)
部分)。 reader.loadBeanDefinitions(configLocations)
,将加载/解析 xml中bean对象的任务委托给了XmlBeanDefinitionReader
对象
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException{
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
复制代码
2-5-2:执行AbstractBeanDefinitionReader
的loadBeanDefinitions(String... locations)
方法
虽然把加载/解析 xml中bean对象的任务委托给了XmlBeanDefinitionReader
对象,但是该方法的具体实现被封装在了XmlBeanDefinitionReader
父类AbstractBeanDefinitionReader
中。
该方法中又是层层调用AbstractBeanDefinitionReader
的loadBeanDefinitions
重载方法,最后进入到loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)
方法中
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//初始化 XmlBeanDefinitionReader 时 设置了 setResourceLoader(this)
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
复制代码
由于篇幅原因loadBeanDefinitions
方法到下篇博客继续跟踪......
总结
-
Spring容器的具体实现对象是
DefaultListableBeanFactory
-
加载/解析我们配置bean对象的xml文件的类的对象是
XmlBeanDefinitionReader
对象(这样说可能不太准确,但是解析入口是在该对象中开始的)
欢迎扫码关注
如果喜欢请关注我公众号【程序倾听者】,说出你的故事!我在这里倾听!
文章原文地址