前言
本章主要内容是由以下部分组成,
- Spring 中容器初始化入口
- 以最经典的 ClassPathXmlApplicationContext 为例,讲解 Spring IoC 的容器初始化过程
在学习源码的过程当中,我想强调两点:
- 一定要学会抓重点,归纳核心类、核心方法、核心步骤。
- 理解类、变量、方法名的命名,Spring 源码的命名是很讲究的,很多时候是自解释的
- 一定要学会看 Java doc,同上,这种顶级的框架的 java doc 描述非常的详尽
Spring 容器初始化入口
启动容器,实际上指的就是实例化 ApplicationContext 的这个动作。只是在不同情况下可能有不同的表现形式。
- ClassPathXmlApplicationContext 通过 XML 配置
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml");
- AnnotationConfigApplicationContext 通过 java config 类配置
@Configuration
@ComponentScan("ric.study.demo.ioc")
public class BeanDemoConfig {public static void main(String... strings) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(BeanDemoConfig.class);
System.out.println("Spring container started and is ready");
...
}
}
类似前面这两种 new ***ApplicationContext
的方式,很少会用于直接的生产开发。一般都是我们自己在 demo 中或者单元测试中会用到。
- WebApplicationContext SpringMVC
这个实际上是我们平常最常用的初始化方式,Spring MVC 中 ServletContext 为 Spring 的 IoC 容器提供了宿主环境。是通过 ContextLoaderListener 的初始化来建立的。
WebApplicationContext 的初始化调用链路:ContextLoaderListener.contextInitialized –> ContextLoader.initWebApplicationContext –> ContextLoader.createWebApplicationContext –> ContextLoader.determineContextClass –> ContextLoader.determineContextClass。
底层是通过反射来实例化的。
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {Class<?> contextClass = determineContextClass(sc);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
这块内容先简要提一下,属于 SpringMVC 的内容,不是我们今天要讲的 Spring IoC 模块的知识。
容器初始化 源码解析
现在让我们正式开始的源码解读。会从最经典的 ClassPathXmlApplicationContext 上下文为起点,来描述整个过程。
在说明之前,我想了想还是觉得把整个 IoC 容器初始化的关键步骤为大家梳理一下,以便于大家能在心里有个大概的脉络,更容易读懂源码,更容易抓住重点。再重复提一句,看源码一定要学会抓重点,归纳核心类、核心方法、核心步骤。
ClassPathXmlApplicationContext 的容器初始化我们大致分为下面几步:
- BeanDefinition 的 Resource 定位
这里的 Resource 定位 是通过继承 ResourceLoader 获得的,ResourceLoader 代表了 加载资源的一种方式,正是策略模式的实现。
- 从 Resource 中解析、载入 BeanDefinition
- BeanDefinition 在 IoC 容器中的注册
前面说了,实例化这个上下文,就是在启动 IoC 容器。那我们肯定要从它的构造函数入手。
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {super(parent);
setConfigLocations(configLocations);
if (refresh) {refresh();
}
}
入参中的 configLocations
在这里就是你 XML 配置文件 的 classpath。
setConfigLocations(configLocations);
我这里不展开讲,内容不复杂,就是把一些带有占位符的地址解析成实际的地址。
再之后就是 refresh()
,我们说的容器初始化,就是在这里面进行的,这里取名为 refresh, 是因为容器启动之后,再调用 refresh()
会刷新 IoC 容器。
这里先放上 IoC 容器初始化的时序图,方便理解,
refresh() 的源码:
@Override
public void refresh() throws BeansException, IllegalStateException {// 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized (this.startupShutdownMonitor) {
// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
prepareRefresh();
// 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,// 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,// 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
// 这块待会会展开说
prepareBeanFactory(beanFactory);
try {
//【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,// 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】// 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
// 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
postProcessBeanFactory(beanFactory);
// 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
// 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
registerBeanPostProcessors(beanFactory);
// 初始化当前 ApplicationContext 的 MessageSource,国际化不是重点,不展开
initMessageSource();
// 初始化当前 ApplicationContext 的事件广播器,这里也不展开了
initApplicationEventMulticaster();
// 从方法名就可以知道,典型的模板方法(钩子方法),// 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)onRefresh();
// 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过
registerListeners();
// 重点,重点,重点
// 初始化所有的 singleton beans
//(lazy-init 的除外)finishBeanFactoryInitialization(beanFactory);
// 最后,广播事件,ApplicationContext 初始化完成
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.
// 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();}
}
}
我会从上述流程中,挑以下几个进行分析,
- prepareRefresh() 创建容器前的准备工作
- obtainFreshBeanFactory() 创建 BeanFactory
- prepareBeanFactory(beanFactory) 对 BeanFactory 进行一些特征的设置工作
- finishBeanFactoryInitialization(beanFactory); 初始化所有的 singleton beans(DI 的入口)
1. prepareRefresh() 创建容器前的准备工作
protected void prepareRefresh() {
// 记录启动时间,// 将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean 类型
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {logger.info("Refreshing" + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
// 校验 xml 配置文件
getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();}
2.★ obtainFreshBeanFactory() 创建 Bean 容器,加载并注册 Bean
IoC 初始化里面最重要的部分。
关键是以下几步,
- 初始化 BeanFactory
- 加载 Bean
- 注册 Bean
- …
注意:这步完成后,Bean 并没有完成初始化,实际的实例并没有被创建。
源码位置:AbstractApplicationContext#obtainFreshBeanFactory()
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等
refreshBeanFactory();
// 返回上一步刚刚创建的 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {logger.debug("Bean factory for" + getDisplayName() + ":" + beanFactory);
}
return beanFactory;
}
源码位置:AbstractRefreshableApplicationContext#refreshBeanFactory()
protected final void refreshBeanFactory() throws BeansException {
// 如果 ApplicationContext 已经加载过 BeanFactory,销毁所有的 Bean,关闭 BeanFactory
// 注意点:应用中 BeanFactory 是可以有多个的,这里可不是说全局是否有 BeanFactory
// 而是说当前的 ApplicationContext 有没有 BeanFactory!if (hasBeanFactory()) {destroyBeans();
closeBeanFactory();}
try {
// 初始化一个 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 用于 BeanFactory 的序列化,一般人应该用不到吧...
beanFactory.setSerializationId(getId());
// 下面是两个重点方法
// 设置 BeanFactory 的两个重要属性
// 是否允许 Bean 覆盖、是否允许循环引用 TODO 2.1
customizeBeanFactory(beanFactory);
// 加载 BeanDefinition 到 BeanFactory 单独拉出来讲
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}
}
catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for" + getDisplayName(), ex);
}
}
看到这里的时候,可以感觉到一个设计思路,ApplicationContext 继承自 BeanFactory,但是 它不应该被理解为 BeanFactory 的实现类,而是说其内部持有一个实例化的 BeanFactory(DefaultListableBeanFactory)。以后所有的 BeanFactory 相关的操作其实是委托给这个实例来处理的。
2.1 customizeBeanFactory
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {if (this.allowBeanDefinitionOverriding != null) {beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
BeanDefinition 的覆盖问题可能会有开发者碰到这个坑,就是在配置文件中定义 bean 时使用了相同的 id 或 name,默认情况下,allowBeanDefinitionOverriding 属性为 null(Boolean 类型),如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖。
循环引用也很好理解:A 依赖 B,而 B 依赖 A。或 A 依赖 B,B 依赖 C,而 C 依赖 A。
默认情况下,Spring 允许循环依赖,当然如果你在 A 的构造方法中依赖 B,在 B 的构造方法中依赖 A 是不行的。
2.2 ★ loadBeanDefinitions(beanFactory) 加载 BeanDefinition
看下这个方法的声明,
/**
* Load bean definitions into the given bean factory, typically through
* delegating to one or more bean definition readers.
* @param beanFactory the bean factory to load bean definitions into
* @throws BeansException if parsing of the bean definitions failed
* @throws IOException if loading of bean definition files failed
* @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
*/
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
在 ClassPathXmlApplicationContext 是按照解析 XML 的加载方式。看 javadoc 的描述,是通过 XmlBeanDefinitionReader
来载入 Bean Definitions。
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// 初始化 Reader 不重要,看下这个方法的 javadoc 就很好理解了
initBeanDefinitionReader(beanDefinitionReader);
// 真正重要的步骤!!// 用 Reader 去加载 XML 配置
loadBeanDefinitions(beanDefinitionReader);
}
loadBeanDefinitions(beanDefinitionReader)
/**
* Load the bean definitions with the given XmlBeanDefinitionReader.
* 看这句注释:this method is just supposed to load and/or register bean definitions.
*/
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {Resource[] configResources = getConfigResources();
if (configResources != null) {reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// 这个分支,通过路径名去获取 Resource,会和上面的方法殊途同归
reader.loadBeanDefinitions(configLocations);
}
}
AbstractBeanDefinitionReader#loadBeanDefinitions(Resource... resources)
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
// 遍历解析 XML 文件,加载 BeanDefinition
counter += loadBeanDefinitions(resource);
}
return counter;
}
接下去的源码不细讲,这里载入分为两大步,
- 一就是通过调用 XML 的解析器获取到 document 对象,完成通用 XML 解析;
- 二就是按照 Spring 的 Bean 规则进行解析。Spring 的 Bean 规则进行解析这个过程是
BeanDefinitionDocumentReader
来实现的,里面包含了各种 Spring Bean 定义规则的处理。
这里我觉得核心知识点就是 Spring Bean 规则的解析,简单点来说,里面包含了我们在 XML 配置的那些信息,怎么解析成容器中 BeanDefinition 的规则和步骤。这部分由于和主要流程关系不大,我就没贴源码解析了,会占掉很大的篇幅,影响阅读和理解。
在这因为 Spring 的 Bean 配置方式有很多,解析配置信息到 BeanDefinition 的实现方式也有很多,XML 又是现在少用的方式,所以关于 XML 中的 Spring Bean 规则的解析的详细源码就先略过了。有兴趣的同学可以阅读《Spring 技术内幕》这本书或者其他的文章书籍。
2.3 注册 Bean
虽然上面说了不讲 XML 解析 成 BeanDefinition 的过程源码。但是上述 loadBeanDefinitions(resource)
包含了我们关键的第三步,注册 Bean。这部分还是需要填一下的。
注意一下前面实例化 Reader 的代码,
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
/**
* Create new XmlBeanDefinitionReader for the given bean factory.
* @param registry the BeanFactory to load bean definitions into,
* in the form of a BeanDefinitionRegistry
*/
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {super(registry);
}
beanDefinitionReader 获取到 beanFactory 的引用,这个引用会在 beanDefinition 被加载完毕要注册的时候使用到。可以看到是因为 BeanDefinitionRegistry
这个接口,赋予了 BeanFactory 注册 BeanDefinition 的特性。
具体执行“注册 Bean”这一动作的源码,按照上述 loadBeanDefinitions(resource)
方法一直走下去的话是在 DefaultBeanDefinitionDocumentReader#processBeanDefinition()
方法中,
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 注册 Bean
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name'" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
源码位置BeanDefinitionReaderUtils#registerBeanDefinition()
/**
* Register the given bean definition with the given bean factory.
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
// 注册
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
// 如果还有别名的,把别名全都注册一遍
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {for (String alias : aliases) {
// 到时候获取的时候,就是先把 Alias 转化成 BeanName,再去获取对应的 Bean
registry.registerAlias(beanName, alias);
}
}
}
上面的registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
,
源码位置DefaultListableBeanFactory#registerBeanDefinition()
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {((AbstractBeanDefinition) beanDefinition).validate();}
catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 注意哦,这里是有关“允许 Bean 覆盖”的逻辑代码
// 记得这个配置 allowBeanDefinitionOverriding
BeanDefinition oldBeanDefinition;
// beanDefinitionMap 是存放所有 BeanDefinition 的容器
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// not null 说明,有重复名称的 bean
if (oldBeanDefinition != null) {if (!isAllowBeanDefinitionOverriding()) {
// 判断是否允许覆盖,不允许直接抛异常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean'" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// 打下 debug log... 用框架定义的 Bean 覆盖用户自定义的 Bean
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean'" + beanName +
"'with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
// 打下 debug log... 用新的 Bean 覆盖旧的 Bean
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean'" + beanName +
"'with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
// 打下 debug log... 用同等的 Bean 覆盖旧的 Bean
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean'" + beanName +
"'with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
// 覆盖了
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 判断是否有其他 Bean 已经开始初始化了
if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)
// 检测创建 Bean 阶段已经开启,需要对 beanDefinitionMap 进行并发控制
synchronized (this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
// 最最最正常的分支
// 注册 到 容器中
this.beanDefinitionMap.put(beanName, beanDefinition);
// 这是一个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
this.beanDefinitionNames.add(beanName);
// 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,// 注意这里是 remove 方法,到这里的 Bean 当然不是手动注册的
// 手动指的是通过调用以下方法注册的 bean:// registerSingleton(String beanName, Object singletonObject)
// 这不是重点,解释只是为了不让大家疑惑。Spring 会在后面 "手动" 注册一些 Bean,// 如 "environment"、"systemProperties" 等 bean,我们自己也可以在运行时注册 Bean 到容器中的
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);
}
}
以上,只是 obtainFreshBeanFactory()
的内容,到这里,BeanFactory 也算是实例化完成了。
这里还是来个分割线。因为接下去会讲 refresh() 方法的后续步骤的知识点,我想读者同学在这里最好最好,回到 前面 refresh()
总述的部分,再看一下。(如果你是一边还打开着 IDE,在对照阅读调试的话,回到最前面 refresh() 方法,再继续往下)
3. prepareBeanFactory(beanFactory)
此方法负责对 BeanFactory 进行一些特征的设置工作,这些特征在代码中都有体现。
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
// BeanFactory 需要加载类,所以需要获得类加载器
// 设置当前 ApplicationContext 的类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 内含 Spel 解释器,暂时不重要
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 注册属性编辑器,暂时不重要
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
// 添加一个 ApplicationContextAwareProcessor,主要针对实现了 Aware 接口的 Bean
// 延伸知识:在 Spring 中我们自己的 bean 可以通过实现 EnvironmentAware 等一系列 Aware 接口,获取到 Spring 内部的一些对象。beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 依赖解析忽略, 设置哪些接口在进行依赖注入的时候应该被忽略
// 通俗来说,下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,// Spring 会通过其他方式来处理这些依赖。beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
/**
* 下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值,* 之前我们说过,"当前 ApplicationContext 持有一个 BeanFactory",这里解释了第一行
* ApplicationContext 还继承了 ResourceLoader、ApplicationEventPublisher、MessageSource
* 所以对于这几个依赖,可以赋值为 this,注意 this 是一个 ApplicationContext
* 那这里怎么没看到为 MessageSource 赋值呢?那是因为 MessageSource 被注册成为了一个普通的 bean
*/
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
// 这个 BeanPostProcessor 也很简单,在 bean 实例化后,如果是 ApplicationListener 的子类,// 这个 postProcessor 的作用就是将其添加到 listener 列表中,可以理解成:注册 事件监听器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
// 这里涉及到特殊的 bean,名为:loadTimeWeaver,AspectJ 相关内容
// 不是这里的重点,放过我
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
// Spring 的“智能”操作,会帮我们默认注册一些有用的 Bean
// 如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
4. ★ finishBeanFactoryInitialization(beanFactory) 实例化所有单例
这里会负责初始化所有的 singleton beans。
Spring 会在这个阶段完成所有的 singleton beans 的实例化。
到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor
接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory)
方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 environment
、systemProperties
等。
剩下的就是初始化 singleton beans 了,我们知道它们是单例的,如果没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans。
源码位置:AbstractApplicationContext#finishBeanFactoryInitialization()
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
// 初始化 "conversionService" 的 bean,此接口用于类型之间的转化,不是重点,放过我,自己去看
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
// 就是为了解析注解的值,没啥重点
if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
// 前面说过的,不是这里的重点
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
// 先初始化 LoadTimeWeaverAware 类型的 bean
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
// 看方法名就知道了,冻结所有 BeanDefinition 的元数据了
// 没什么别的目的,因为到这一步的时候,Spring 已经开始预初始化 singleton beans 了,// 肯定不希望这个时候还出现 bean 定义解析、加载、注册。beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
// 开始初始化,进来看吧,重点在里面
beanFactory.preInstantiateSingletons();}
源码位置:DefaultListableBeanFactory#preInstantiateSingletons()
@Override
public void preInstantiateSingletons() throws BeansException {if (this.logger.isDebugEnabled()) {this.logger.debug("Pre-instantiating singletons in" + this);
}
// copy 一个包含所有 BeanName 的集合副本
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// 触发所有非懒加载的 singleton beans 的初始化
for (String beanName : beanNames) {
// Bean 可能有继承 parent 的关系,获取合并后的 RootBeanDefinition
// 这个知识点用的很少的
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非抽象、非懒加载的 singletons
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// FactoryBean 知识点,不了解的看另一篇文章或者自己 google
if (isFactoryBean(beanName)) {
// FactoryBean 会在 beanName 前面加前缀 "&"
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
// SmartFactoryBean, 非重点,没深入了解,放过我
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {return ((SmartFactoryBean<?>) factory).isEagerInit();}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {getBean(beanName);
}
}
else {
// 正常的 bean 都到这里来了,重点哦,里面进行初始化了
// 调用链很复杂,单独拉出来讲,先继续
getBean(beanName);
}
}
}
// 前面流程走完,说明所有的非懒加载 singletonBean 完成了初始化
// Trigger post-initialization callback for all applicable beans...
// 看注释就懂了,如果我们定义的 bean 是实现了 SmartInitializingSingleton 接口的,// 那么在这里得到回调,忽略它吧。for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {smartSingleton.afterSingletonsInstantiated();
}
}
}
}
小知识点 关于 lazy-init
ApplicationContext 实现的默认行为就是在启动时将所有 singleton bean 提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的 singleton bean。通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天)。
有时候这种默认处理可能并 不是 你想要的。如果你不想让一个 singleton bean 在 ApplicationContext 实现在初始化时被提前实例化,那么可以将 bean 设置为延迟实例化。一个延迟初始化 bean 将告诉 IoC 容器是在启动时还是在第一次被用到时实例化。
需要说明的是,如果一个 bean 被设置为延迟初始化,而另一个非延迟初始化的 singleton bean 依赖于它,那么当 ApplicationContext 提前实例化 singleton bean 时,它必须也确保所有上述 singleton 依赖 bean 也被预先初始化,当然也包括设置为延迟实例化的 bean。因此,如果 Ioc 容器在启动的时候创建了那些设置为延迟实例化的 bean 的实例,你也不要觉得奇怪,因为那些延迟初始化的 bean 可能在配置的某个地方被注入到了一个非延迟初始化 singleton bean 里面。
结语
以上,本文就是关于 Spring IoC 容器初始化的主要内容。
Spring IoC 的设计中,Bean 定义的解析和 Bean 的依赖注入,是两个独立的过程,前面所有内容讲的就是 IoC 容器的初始化,资源定位、载入以及解析 BeanDefinition 并且注册。
最后一步的实例化所有单例,引入了 getBean()
方法,这就是 Spring IoC 依赖注入的入口。也是下节源码解读的主要内容。
另外说一句,上面的源码解析,肯定不会是完备的,只是提取了我认为重要的东西。
如有疏漏,敬请谅解和自己查阅相关资料学习。如果错误,敬请指正!
本文由博客一文多发平台 OpenWrite 发布!