Loading

Spring容器创建过程分析

这篇文章中,主要讲解了SpringBoot的启动流程,其中还涉及到Spring的容器创建过程,那么本文就来讲解一下Spring容器的创建过程

环境:SpringBoot 2.4.2

一般情况下,我们可以用xml配置文件或者配置类来创建容器,涉及到ClassPathXmlApplicationContextAnnotationConfigApplicationContext这两个类。我们查看这两个类的源代码,在构造方法中,可以看到都调用了父类AbstractApplicationContextrefresh()方法,而这个方法也就是Spring容器的创建和刷新过程。所以,我们从这个方法入手来分析

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

        // Prepare this context for refreshing.
	prepareRefresh();

	// Tell the subclass to refresh the internal bean factory.
	ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

	// Prepare the bean factory for use in this context.
	prepareBeanFactory(beanFactory);

	try {
	    // Allows post-processing of the bean factory in context subclasses.
	    postProcessBeanFactory(beanFactory);

	    StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
	    // Invoke factory processors registered as beans in the context.
	    invokeBeanFactoryPostProcessors(beanFactory);

	    // Register bean processors that intercept bean creation.
	    registerBeanPostProcessors(beanFactory);
	    beanPostProcess.end();

	    // Initialize message source for this context.
	    initMessageSource();

	    // Initialize event multicaster for this context.
	    initApplicationEventMulticaster();

	    // Initialize other special beans in specific context subclasses.
	    onRefresh();

	    // Check for listener beans and register them.
	    registerListeners();

	    // Instantiate all remaining (non-lazy-init) singletons.
	    finishBeanFactoryInitialization(beanFactory);

	    // Last step: publish corresponding event.
	    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();
	    contextRefresh.end();
	}
    }
}

1. BeanFactory预准备

我们可以在refresh方法处加上断点,开启debug,进行调试

1.1 prepareRefresh()

方法内第一行是线程安全的锁机制,我们先关注prepareRefresh();这一行代码,这是做刷新前的预处理工作。step into进入这个方法

protected void prepareRefresh() {
    // Switch to active.
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    if (logger.isDebugEnabled()) {
	if (logger.isTraceEnabled()) {
	    logger.trace("Refreshing " + this);
	} else {
	    logger.debug("Refreshing " + getDisplayName());
	}
    }

    // Initialize any placeholder property sources in the context environment.
    initPropertySources();

    // Validate that all properties marked as required are resolvable:
    // see ConfigurablePropertyResolver#setRequiredProperties
    getEnvironment().validateRequiredProperties();

    // Store pre-refresh ApplicationListeners...
    if (this.earlyApplicationListeners == null) {
	this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
    } else {
	// Reset local application listeners to pre-refresh state.
	this.applicationListeners.clear();
	this.applicationListeners.addAll(this.earlyApplicationListeners);
    }

    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    this.earlyApplicationEvents = new LinkedHashSet<>();
}

在这个方法内部,除了记录一些状态,打印日志以外,我们会遇到一个方法initPropertySources(),这个方法会初始化一些属性设置,AbstractApplicationContext的子类可以重写这个方法来自定义属性设置方法

另外,getEnvironment().validateRequiredProperties();会检验属性的合法

this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);保存容器中一些早期的事件监听器

this.earlyApplicationEvents = new LinkedHashSet<>();会保存容器中一些早期的事件

以上便是prepareRefresh()方法的主要工作

1.2 obtainFreshBeanFactory()

在执行完prepareRefresh()方法之后,会进行ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();方法来获取BeanFactory。step into进入这个方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

首先执行refreshBeanFactory();,这个方法会刷新BeanFactory。进入这个方法,我们来到了GenericApplicationContext这个类中,在这个类中,会首先执行this.beanFactory = new DefaultListableBeanFactory();创建一个BeanFactory对象,然后在refreshBeanFactory()方法中为这个对象设置序列化id

最后执行getBeanFactory()方法,这个方法会返回上一步创建的BeanFactory对象(DefaultListableBeanFactory)。

可以看到,BeanFactory对象的创建是GenericApplicationContext这个类创建的

1.3 prepareBeanFactory(beanFactory)

在执行完obtainFreshBeanFactory()方法后,创建并获取到了一个BeanFactory对象,接下来就会执行prepareBeanFactory(beanFactory);这一行代码,这是BeanFactory的预准备工作,会对上一步创建的BeanFactory对象进行一些设置。step into这个方法

  1. 在这个方法中,会设置BeanFactory的类加载器,支持表达式解析器等等

  2. 还会添加部分BeanPostProcessor(ApplicationContextAwareProcessor)

  3. 设置忽略的自动装配的接口,比如EnvironmentAware、EmbeddedValueResolverAware等等,设置这些是为了让这些接口的实现类不能通过接口类型实现自动注入

  4. 注册可以解析的自动装配,表示我们能直接在任何组件中自动注入BeanFactoryResourceLoaderApplicationEventPublisherApplicationContext这些组件

  5. 添加BeanPostProcessor(ApplicationListenerDetector)

  6. 添加编译时的AspectJ支持

  7. 注册一些能用的组件:environment(ConfigurableEnvironment)、systemProperties(Map<String, Object>)、systemEnvironment(Map<String, Object>)、applicationStartup(ApplicationStartup)

1.4 postProcessBeanFactory(beanFactory)

在设置完BeanFactory对象之后,会执行postProcessBeanFactory(beanFactory);,这是BeanFactory对象准备完成之后进行的后置处理工作

AbstractApplicationContext的子类可以重写这个方法来对上一步已经准备完成的BeanFactory做进一步的设置

以上便是BeanFactory的创建及预准备工作,接下来就要使用BeanFactory对象来创建容器中的组件

2. 执行BeanFactoryPostProcessor

在对BeanFactory的预准备工作进行完之后,就会执行BeanFactoryPostProcessorBeanFactoryPostProcessorBeanFactory的后置处理器,是在BeanFactory标准初始化之后执行的拦截调用

2.1 invokeBeanFactoryPostProcessors(beanFactory)

执行BeanFactory的后置处理器,step into这个方法

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    if (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
	beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
	beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

我们查看第一行的代码,进入invokeBeanFactoryPostProcessors()方法。首先,需要注意的是,对于BeanFactoryPostProcessor,有两种不同的类,一个是BeanFactoryPostProcessor,另一个是BeanDefinitionRegistryPostProcessor,其中,前者是后者的父类

方法中,首先执行BeanDefinitionRegistryPostProcessor的方法

  1. 获取所有的BeanDefinitionRegistryPostProcessor

  2. 首先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor

  3. 再执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor

  4. 最后执行其他的BeanDefinitionRegistryPostProcessor

再执行BeanFactoryPostProcessor的方法,步骤和以上4步类似

  1. 获取所有的BeanFactoryPostProcessor

  2. 对所有的BeanFactoryPostProcessor进行分类,分为实现了PriorityOrdered优先级接口的、实现了Ordered顺序接口的,以及其他

  3. 先后执行实现了PriorityOrdered优先级接口的、实现了Ordered顺序接口的,以及其他的BeanFactoryPostProcessor

总之,这一步就是执行BeanFactory的后置处理器

2.2 BeanFactoryPostProcessor的来源

我们可以通过ApplicationContextaddBeanFactoryPostProcessor()方法来手动添加自定义的拦截器

另外,系统默认了一些BeanFactoryPostProcessor。比如,ConfigurationClassPostProcessor用来处理@Configuration注解标注的Spring配置类

3. 注册BeanPostProcessors

BeanPostProcessor是Bean的后置处理器,用来拦截Bean的创建过程

在Spring中,存在着多种BeanPostProcessor类型,除了BeanPostProcessor,还有DestructionAwareBeanPostProcessorInstantiationAwareBeanPostProcessorMergedBeanDefinitionPostProcessorSmartInstantiationAwareBeanPostProcessor。对于不同的BeanPostProcessor,在Bean创建前后的执行时机是不同的

step into registerBeanPostProcessors(beanFactory);这一行代码

在方法中

  1. 获取所有的BeanPostProcessor

  2. 和获取BeanFactoryPostProcessor的步骤一样,对得到的所有BeanPostProcessor进行分类,分为实现了PriorityOrdered优先级接口的、实现了Ordered顺序接口的,以及其他

  3. 先后注册实现了PriorityOrdered优先级接口的、实现了Ordered顺序接口的,以及其他的BeanPostProcessor

  4. 最后注册MergedBeanDefinitionPostProcessor

  5. 最终注册一个ApplicationListenerDetector,在Bean创建完成后用来检查是否是ApplicationListener

整个注册的过程就是简单地将BeanPostProcessor实例保存到BeanFactory对象的beanPostProcessors属性中

4. 初始化MessageSource

在注册完BeanPostProcessor之后,会初始化MessageSource组件,这个组件主要做国际化功能,消息绑定,消息解析。step into initMessageSource();这一行代码

在方法中

  1. 首先获取BeanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();

  2. 看容器中是否有id为messageSource,类型为MessageSource的组件。如果有,则赋值给messageSource变量,如果没有,就立即创建一个DelegatingMessageSource

  3. 把创建好的MessageSource注册到容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource
    beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);

5. 初始化事件派发器、监听器

5.1 initApplicationEventMulticaster()

在初始化MessageSource之后,就执行initApplicationEventMulticaster();来初始化事件派发器。step into 这个方法

  1. 首先获取BeanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();

  2. 看容器中是否有名称为applicationEventMulticaster,类型为ApplicationEventMulticaster的组件。如果有,从BeanFactory中获取这个组件,如果没有,就立即创建一个SimpleApplicationEventMulticaster

  3. 将创建好的SimpleApplicationEventMulticaster注册到容器中
    beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);

5.2 onRefresh()

onRefresh()方法留给子容器(子类)进行重写,在容器刷新的时候可以自定义一些逻辑

5.3 registerListeners()

registerListeners()方法会给容器中注册所有项目的ApplicationListener。step into 这个方法

  1. 从容器中获取所有的ApplicationListener组件
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);

  2. 将获取到的每个监听器添加到事件派发器中

for (String listenerBeanName : listenerBeanNames) {
    getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
  1. 如果存在早期事件,就派发这些早期产生的事件

以上便是对于事件派发器和事件监听器的初始化工作

6. 创建Bean

在初始化事件派发器和监听器并进行注册之后,就会进行初始化其余单实例Bean的工作。step into finishBeanFactoryInitialization(beanFactory);这行代码

在这个方法中,一开始只是做BeanFactory的配置工作,最后一行beanFactory.preInstantiateSingletons();才初始化其余的单实例Bean。step into这个方法

  1. 获取定义好的所有Bean名称
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

  2. 对每个Bean名称,依次进行创建对象和初始化

    1. 首先获取Bean的定义信息,RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    2. 再判断Bean不是抽象的,是单实例的,不是懒加载的
      • 如果Bean是FactoryBean,就调用工厂Bean的方法进行创建
      • 如果Bean不是FactoryBean,就调用getBean(beanName);创建对象。这里的getBean()方法就是我们使用IOC容器获取Bean的getBean()方法,也就是容器创建Bean的过程,详见6.1
  3. 所有的Bean都通过getBean()方法创建完成后,检查所有的Bean是否实现了SmartInitializingSingleton接口,如果是,就执行接口的afterSingletonsInstantiated()方法

6.1 getBean方法

getBean(beanName)方法就是容器创建特定Bean的过程。对于这个方法,我们step into,来到了AbstractBeanFactory类中,这个方法调用了doGetBean(name, null, null, false)方法。

在这个方法中

  1. 首先获取缓存中保存的单实例Bean。如果能获取到,说明这个Bean之前已经被创建过了(所有创建过的单实例Bean都会被缓存起来)
    最终是从private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);这里获取单实例Bean,也就是单实例Bean的缓存

  2. 缓存中获取不到,就开始Bean的创建对象流程

    1. 标记当前Bean已经被创建
    2. 获取Bean的定义信息,RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    3. 获取当前Bean依赖的其他Bean(depends-on属性,不是属性注入),String[] dependsOn = mbd.getDependsOn();。如果有,就用getBean()方法把依赖的Bean先创建出来
    4. 最终创建单实例Bean
      1. 调用createBean(beanName, mbd, args)创建Bean
      2. 在上述方法中调用Object bean = resolveBeforeInstantiation(beanName, mbdToUse);,让InstantiationAwareBeanPostProcessor先拦截返回代理对象,会先触发postProcessBeforeInstantiation()方法,如果此方法返回不为空,则继续触发postProcessAfterInitialization()方法
      3. 真正创建Bean】 如果resolveBeforeInstantiation()方法没有返回代理对象,则调用Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean
        1. 创建Bean实例instanceWrapper = createBeanInstance(beanName, mbd, args);创建Bean实例,内部是使用工厂方法或者对象的构造器创建出Bean实例
        2. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);调用MergedBeanDefinitionPostProcessorpostProcessMergedBeanDefinition()方法
        3. Bean属性赋值populateBean(beanName, mbd, instanceWrapper);为Bean实例的属性赋值
          1. 赋值之前获取到InstantiationAwareBeanPostProcessor后置处理器,执行postProcessAfterInstantiation()方法
          2. 获取到InstantiationAwareBeanPostProcessor后置处理器,执行postProcessProperties()方法
          3. 最后对Bean进行赋值,applyPropertyValues(beanName, mbd, bw, pvs);,其中是调用setter等方法进行赋值
        4. Bean初始化exposedObject = initializeBean(beanName, exposedObject, mbd);进行Bean的初始化
          1. 【执行Aware接口方法】 首先执行Aware接口的方法,invokeAwareMethods(beanName, bean);,判断Bean是否是BeanNameAwareBeanClassLoaderAwareBeanFactoryAware其中的一种,如果是就调用相应方法
          2. 【执行后置处理器初始化之前的方法】 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);,其中调用BeanPostProcessor.postProcessBeforeInitialization()方法
          3. 【执行初始化方法】 invokeInitMethods(beanName, wrappedBean, mbd);,其中会判断Bean是否实现了InitializingBean,如果是就执行接口规定的初始化方法((InitializingBean) bean).afterPropertiesSet();,如果不是就判断是否自定义了初始化方法,如果有就执行自定义的初始化方法invokeCustomInitMethod(beanName, bean, mbd);
          4. 【执行后置处理器初始化之后的方法】 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);,其中调用BeanPostProcessor.postProcessAfterInitialization()方法
          5. 最后初始化完成,返回
        5. 注册Bean的销毁方法(在容器关闭时调用,对应于初始化方法),registerDisposableBeanIfNecessary(beanName, bean, mbd);
        6. doCreateBean()方法运行完毕,最后返回创建好的Bean
      4. createBean()方法运行完毕,创建出了Bean
      5. 将创建出的Bean添加到单实例Bean的缓存中,也就是这个singletonObjects变量(Map类型)

以上便是getBean()方法的执行过程,也是容器创建Bean的过程

7. 容器创建完成

之前通过getBean()方法将所有Bean创建出来,期间还触发了各种后置处理器的回调函数。那么,在这之后,就要执行finishRefresh();来完成BeanFactory容器的初始化创建工作,IOC容器正式创建完成

在这方法内部

  1. 初始化和生命周期相关的处理器,initLifecycleProcessor();
    如果容器中已经有了名字为lifecycleProcessor且类型为LifecycleProcessor的处理器,就直接获取到这个处理器
    如果容器中不存在,就创建一个DefaultLifecycleProcessor类型的处理器,且注册到容器中

  2. 获取到上一步的生命周期处理器(监听BeanFactory),执行回调方法,getLifecycleProcessor().onRefresh();

  3. 发布容器刷新完成事件,publishEvent(new ContextRefreshedEvent(this));

  4. LiveBeansView.registerApplicationContext(this);

8. 总结

Spring容器的启动过程如上文所示,很复杂,这里总结几个比较重要的点

  1. Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息

    • xml注册Bean
    • 注解注册Bean
  2. Spring容器在合适的时候创建这些Bean

    • (多实例,或懒加载)在用到这个Bean的时候:使用getBean()方法创建Bean,创建好之后放到容器中
    • (单实例,非懒加载)容器启动时统一创建所有Bean:在finishBeanFactoryInitialization()方法中完成,内部对于每个Bean使用getBean()方法创建
  3. 后置处理器:
    每个Bean创建时,都会使用后置处理器进行处理,来增强Bean的功能
    比如:AutowiredAnnotationBeanPostProcessor处理自动注入,AnnotationAwareAspectJAutoProxyCreator做AOP功能,创建代理对象

  4. 事件驱动模型
    ApplicationListener事件监听,ApplicationEventMulticaster事件派发

posted @ 2021-03-02 19:41  Kinopio  阅读(324)  评论(0编辑  收藏  举报