上文我们通过new ClassPathXmlApplicationContext("applicationContext.xml");这段代码看了下Spring是如何将Xml里面内容注入到Java对象中,并通过context.getBean("jmUser");方式获得了一个对象实例,而避开使用new 来耦合。今天我们就来看看Spring是如何做到的呢?
上图是AbstractApplicationContext的类图,dedug跟踪这段代码
new ClassPathXmlApplicationContext("applicationContext.xml");
ClassPathXmlApplicationContext构造方法
/*** 根据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);// 默认构造trueif (refresh) {// 进入核心方法refresh();}}
1、初始化环境变量相关信息
发现最终进入
/*** 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、设置配置文件的位置
/*** 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方法
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、初始化BeanFactoryConfigurableListableBeanFactory 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、实例化:非兰加载BeanfinishBeanFactoryInitialization(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是怎样利用这些扩展点给我么提供开箱即用的功能的。