本章主要内容是由以下部分组成,
在学习源码的过程当中,我想强调两点:
启动容器,实际上指的就是实例化ApplicationContext的这个动作。只是在不同情况下可能有不同的表现形式。
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml");
@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中或者单元测试中会用到。
这个实际上是我们平常最常用的初始化方式,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 的容器初始化我们大致分为下面几步:
这里的Resource定位 是通过继承ResourceLoader 获得的,ResourceLoader代表了 加载资源的一种方式,正是策略模式的实现 。
前面说了,实例化这个上下文,就是在启动 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容器初始化的时序图,方便理解,
@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();
}
}
}
我会从上述流程中,挑以下几个进行分析,
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>();
}
关键是以下几步,
注意:这步完成后,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 相关的操作其实是委托给这个实例来处理的 。
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类型),如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖 。
看下这个方法的声明,
/**
* 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;
}
接下去的源码不细讲,这里载入分为两大步,
BeanDefinitionDocumentReader
这里我觉得核心知识点就是Spring Bean规则的解析,简单点来说,里面包含了我们在XML配置的那些信息,怎么解析成容器中 BeanDefinition的规则和步骤。这部分由于和主要流程关系不大,我就没贴源码解析了,会占掉很大的篇幅,影响阅读和理解。
在这因为Spring 的 Bean配置方式有很多,解析配置信息到BeanDefinition的实现方式也有很多,XML又是现在少用的方式,所以关于XML中的Spring Bean规则的解析的详细源码就先略过了。有兴趣的同学可以阅读《Spring 技术内幕》这本书或者其他的文章书籍。
虽然上面说了不讲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() 方法,再继续往下)
此方法负责对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());
}
}
这里会负责初始化所有的 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 发布!