Spring源码:ApplicationContext之提前加载单例Bean

一、介绍

  标题中强调指出ApplicationContext,是因为使用Spring框架有两种方式:BeanFactory和ApplicationContext,代码如下:

	// beanFactory方式
    @Test
    public void beanFactoryTest() {
        Resource classPathResource = new ClassPathResource("applicationContext.xml");
        BeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);
    }

	// ApplicationContext方式
    @Test
    public void awareTest() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
    }

它们的区别是:BeanFactory在初始化的时候,不会加载任何bean实例;而ApplicationContext初始化的时候,会提前加载xml中配置的所有单例bean
   我们本篇的目的,是为了探究ApplicationContext初始化的时候,在哪个步骤加载这些单例bean的。

二、源码分析

1. ApplicationContext初始化入口

以下是ApplicationContext初始化的经典入口代码:

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 1. 准备刷新的上下文环境
			prepareRefresh();

			// 2. 初始化BeanFactory,并进行XML文件的加载
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 3. 对BeanFactory进行各种功能填充
			prepareBeanFactory(beanFactory);

			try {
				// 4. 子类覆盖犯法做额外的处理
				postProcessBeanFactory(beanFactory);

				// 5. 调用BeanFactory后处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// 6. 注册bean后处理器,在调用getBean的时候回调这些bean后处理器的方法
				registerBeanPostProcessors(beanFactory);

				// 7. 为上下文初始化Message源
				initMessageSource();

				// 8. 初始化事件多播器
				initApplicationEventMulticaster();

				// 9. 留给子类初始化其他bean
				onRefresh();

				// 10. 注册监听器
				registerListeners();

				// 11. 初始化剩下的单例Bean(非惰性的)
				finishBeanFactoryInitialization(beanFactory);

				// 12. 最后一步,发布通知事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 销毁已经创建的单例,以避免挂起资源。
				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();
			}
		}
	}

与本文相关的代码在第11步,加载剩下的单例Bean。我们由此入口来开始分析~

2. 完成BeanFactory实例化

进入到AbstractApplicationContext类的finishBeanFactoryInitialization方法


	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// 1.初始化此上下文的ConversionService
		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));
		}

		// 2.注册嵌入式值解析器(用于解析注解标注的属性值)
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// 3.初始化LoadTimeWeaverAware
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// 4.停止使用临时类加载器进行类型匹配
		beanFactory.setTempClassLoader(null);

		// 5.允许缓存所有bean定义元数据,而不期望有进一步的更改。
		beanFactory.freezeConfiguration();

		// 6.实例化所有剩余的(非lazy-init)单例。
		beanFactory.preInstantiateSingletons();
	}

前面几个步骤看不懂没关系,我们重点在第6步,实例化所有非懒加载的单例Bean

懒加载的意思就是,容器启动时要不要加载某个bean,可以通过bean标签中的lazy-init属性配置,默认值为false,即非懒加载(容器启动就加载该bean)


<bean id="person" class="com.kaka.spring.beans.Person" lazy-init="true"/>

3. 加载所有非懒加载的单例Bean

	public void preInstantiateSingletons() throws BeansException {
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Pre-instantiating singletons in " + this);
		}
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// 1. 实例化所有非懒加载的单例Bean
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 1.1 FactoryBean类型的bean
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					// 1.2 其他类型的bean
					getBean(beanName);
				}
			}
		}

		// 2. 回调SmartInitializingSingleton类型Bean的afterSingletonsInstantiated方法
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

以上代码来自于DefaultListableBeanFactory类的preInstantiateSingletons方法。看着代码量挺多,其实就干了两件事儿:

  • 实例化所有非懒加载的Bean
  • 回调SmartInitializingSingleton类型Bean的afterSingletonsInstantiated方法

实例化bean的逻辑都在上面的getBean方法中,里面无非是创建了一个Bean实例、给Bean实例填充属性信息、调用bean实例的初始化方法等等,这些不是本章讨论的重点。

三、收获

其实到这儿就结束了,从中我们可以了解到以下几点

  1. 实例化所有非懒加载Bean的入口在:AbstractApplicationContext类的finishBeanFactoryInitialization方法,也就是容器初始化的第11步(倒数第2步)。
    如果你遇到有些你配置的Bean没有在容器中,可以从这个入口进行排查~
  2. 所有需要加载的beanName都保存在:DefaultListableBeanFactory类的beanDefinitionNames属性中
/** List of bean definition names, in registration order */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
  1. 如果想要等所有Bean都初始化完成之后执行一些操作,可以新建一个类实现SmartInitializingSingleton接口的afterSingletonsInstantiated方法,把这些步骤写在这个方法中。并把这个类配置成一个Bean
    因为我们从源码中也可以看到,所有Bean循环实例化之后,又循环所有Bean实例挑出SmartInitializingSingleton类型的Bean回调这些Bean实例的afterSingletonsInstantiated方法
@Component
public class MySmartInitializingSingleton implements SmartInitializingSingleton {
    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("所有的bean都初始化完成了...");
    }
}

你可能感兴趣的:(spring源码,初始化所有Bean之后,所有Bean,所有Bean加载完成)