本章主要内容是由如下部分组成,java
在学习源码的过程中,我想强调两点:spring
启动容器,实际上指的就是实例化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中或者单元测试中会用到。app
这个其实是咱们日常最经常使用的初始化方式,Spring MVC 中 ServletContext 为 Spring 的 IoC容器提供了宿主环境。是经过ContextLoaderListener 的初始化来创建的。框架
WebApplicationContext 的初始化调用链路:ContextLoaderListener.contextInitialized --> ContextLoader.initWebApplicationContext --> ContextLoader.createWebApplicationContext --> ContextLoader.determineContextClass --> ContextLoader.determineContextClass。编辑器
底层是经过反射来实例化的。ide
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 上下文为起点,来描述整个过程。post
在说明以前,我想了想仍是以为把整个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();
}
}
}
复制代码
我会从上述流程中,挑如下几个进行分析,
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>();
}
复制代码
IoC初始化里面最重要的部分。
关键是如下几步,
注意:这步完成后,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类型),若是在同一配置文件中重复了,会抛错,可是若是不是同一配置文件中,会发生覆盖。
循环引用也很好理解:A 依赖 B,而 B 依赖 A。或 A 依赖 B,B 依赖 C,而 C 依赖 A。
默认状况下,Spring 容许循环依赖,固然若是你在 A 的构造方法中依赖 B,在 B 的构造方法中依赖 A 是不行的。
看下这个方法的声明,
/** * 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定义规则的处理。这里我以为核心知识点就是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 依赖注入的入口。也是下节源码解读的主要内容。
另外说一句,上面的源码解析,确定不会是完备的,只是提取了我认为重要的东西。
若有疏漏,敬请谅解和本身查阅相关资料学习。若是错误,敬请指正!