上文我们通过new ClassPathXmlApplicationContext("applicationContext.xml");这段代码看了下Spring是如何将Xml里面内容注入到Java对象中,并通过context.getBean("jmUser");方式获得了一个对象实例,而避开使用new 来耦合。今天我们就来看看Spring是如何做到的呢?
上图是AbstractApplicationContext的类图,dedug跟踪这段代码
new ClassPathXmlApplicationContext("applicationContext.xml");
ClassPathXmlApplicationContext构造方法
java
/**
* 根据xml路径,创建一个ClassPathXmlApplicationContext实例
* Create a new ClassPathXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of resource locations
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 调用父类构造方法,主要是初始化环境变量相关信息,核心代码在 AbstractApplicationContext 类中
super(parent);
// 设置配置文件的位置 ApplicationContext的实现可能会使用默认的配置文件位置。
setConfigLocations(configLocations);
// 默认构造true
if (refresh) {
// 进入核心方法
refresh();
}
}
1、初始化环境变量相关信息
发现最终进入
java
/**
* Create a new AbstractApplicationContext with no parent.
* 创建一个没有父容器的AbstractApplicationContext的实例
*/
public AbstractApplicationContext() {
// 返回一个 PathMatchingResourcePatternResolver(this)实例
this.resourcePatternResolver = getResourcePatternResolver();
}
/**
* Create a new AbstractApplicationContext with the given parent context.
* @param parent the parent context
*/
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
// 将父容器复制给成员变量 parent,如果parent不为空且属于ConfigurableEnvironment类型则合并环境
setParent(parent);
}
2、设置配置文件的位置
java
/**
* Set the config locations for this application context.
* <p>If not set, the implementation may use a default as appropriate.
* 配置了配置文件的位置
* 如果未设置配置位置,某些ApplicationContext的实现可能会使用默认的配置文件位置。
* 例如,ClassPathXmlApplicationContext如果没有指定配置位置,会尝试查找类路径下的applicationContext.xml文件。
*/
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
// getEnvironment().resolveRequiredPlaceholders(path),从路径中解析展位福${}参数
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
/**
* Resolve the given path, replacing placeholders with corresponding
* environment property values if necessary. Applied to config locations.
* @param path the original file path
* @return the resolved file path
* @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)
*/
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
return this.propertyResolver.resolveRequiredPlaceholders(text);
}
3、进入refresh方法
java
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing. 1、初始化上下文信息
prepareRefresh();
// Tell the subclass to refresh the internal bean factory. 2、解析类Xml、初始化BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context. 3、准备BeanFactory内容
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses. 4、扩展点加一:空实现,主要用于处理特殊Bean的后置处理器
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context. 5、spring bean容器的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation. 6、注册bean的后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context. 7、初始化消息源
initMessageSource();
// Initialize event multicaster for this context. 8、初始化事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses. 9、扩展点加一:空实现;主要是在实例化之前做些bean初始化扩展
onRefresh();
// Check for listener beans and register them. 10、初始化监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons. 11、实例化:非兰加载Bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event. 12、发布相应的事件通知
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();
}
}
}
整个流程可以分为以下几个主要步骤:
- 初始化上下文环境信息。
- 解析XML配置文件,创建并初始化
BeanFactory
。 - 设置BeanFactory的类加载器,注册一些默认的环境Bean。
- 提供扩展点用于对BeanFactory进行进一步的定制。
- 调用BeanFactory的后置处理器。
- 注册Bean的后置处理器。
- 初始化消息源,用于国际化支持。
- 初始化事件广播器,用于发布事件。
- 提供扩展点用于在刷新上下文时做一些特殊的初始化。
- 检查并注册监听器Bean。
- 实例化所有剩余的单例Bean(非懒加载)。
- 发布相应的事件通知,表示上下文刷新完成。
步骤概览
1. prepareRefresh()
prepareRefresh();
prepareRefresh()
方法用于初始化上下文环境信息,包括设置启动时间、活动状态等基本属性。它确保在刷新过程中,应用上下文处于正确的状态。
2. obtainFreshBeanFactory()
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
该方法解析XML配置文件,创建并初始化BeanFactory
,并载入Bean定义。它是Spring应用上下文初始化的关键步骤之一。
3. prepareBeanFactory(beanFactory)
prepareBeanFactory(beanFactory);
此步骤设置BeanFactory的类加载器,并注册一些默认的环境Bean,如类加载器、表达式解析器等。它确保BeanFactory在上下文中能够正确工作。
4. postProcessBeanFactory(beanFactory)
postProcessBeanFactory(beanFactory);
这是一个扩展点,通常为空实现。开发者可以在子类中重写该方法,对BeanFactory进行进一步的定制,如添加额外的Bean定义或修改现有的Bean定义。
5. invokeBeanFactoryPostProcessors(beanFactory)
invokeBeanFactoryPostProcessors(beanFactory);
该方法调用BeanFactory的后置处理器,这些处理器可以在Bean实例化之前对Bean定义进行修改或增加新的Bean定义。
6. registerBeanPostProcessors(beanFactory)
registerBeanPostProcessors(beanFactory);
在此步骤中,Spring注册Bean的后置处理器,这些处理器会在Bean的创建过程中拦截并进行处理,如执行依赖注入和初始化回调等。
7. initMessageSource()
initMessageSource();
该方法初始化消息源,用于支持国际化(i18n)。它允许应用程序根据用户的语言环境显示不同的消息。
8. initApplicationEventMulticaster()
initApplicationEventMulticaster();
Spring使用事件广播器来发布和监听应用程序事件。该方法初始化事件广播器,确保事件能够在应用上下文中正确传播。
9. onRefresh()
onRefresh();
这是另一个扩展点,通常为空实现。开发者可以在子类中重写该方法,在刷新上下文时执行一些特殊的初始化操作。
10. registerListeners()
registerListeners();
该方法检查并注册监听器Bean,用于监听和处理应用程序事件。
11. finishBeanFactoryInitialization(beanFactory)
finishBeanFactoryInitialization(beanFactory);
此步骤实例化所有剩余的单例Bean(非懒加载)。它确保所有Bean都已准备就绪,可以在应用程序中使用。
12. finishRefresh()
finishRefresh();
最后,Spring发布相应的事件通知,表示上下文刷新已完成。此步骤通常包括发布ContextRefreshedEvent
事件,通知所有监听器上下文已刷新。
总结
本章主要通过断点源码,一步步跟踪到refresh方法,然后整体跟踪了refresh的具体步骤,每一步大概干了什么内容,后面我们将一个一个方法深入讨论,具体做了什么?预留了什么扩展点。我们在开发中怎么去使用这些扩展点。以及后面SpringBoot和SpringCloud是怎样利用这些扩展点给我么提供开箱即用的功能的。