Spring IoC加载过程/Bean生命周期源码剖析

149 阅读12分钟

从这篇文章开始,就开始对Spring的源码进行分析,那就先从IoC开始,let‘s go!

image.png

首先如果大家想去自己看源码,可以去这里:github.com/spring-proj…

我这里读的是6.2.x的Spring源码,读源码的话我就觉得不用所有都看,就去看几个重要的接口和方法

1. IoC容器初始化

要了解IoC容器的加载过程,本质上就是容器启动的过程。 在spring-context-support-AbstractApplicationContext描述了整个容器的初始化流程,那refresh() 方法是这一步的关键。refresh方法是Spring容器启动的核心方法,整个refresh方法里大概有12个关键步骤。

Editor \_ Mermaid Chart-2025-04-03-040100.png

步骤很多,但整体可划分为2部分,前六步 --> BeanFactory相关、后六步-->Bean初始化&事件广播,我们就分步来介绍一下。

1.1 BeanFactory相关

1.1.1 prepareRefresh()

这个方法主要是Spring容器初始化上下文环境,确保Spring容器可以正常运行。下面是具体的源码:

protected void prepareRefresh() {
    // Switch to active.
    this.startupDate = System.currentTimeMillis();// 记录Spring容器启动的时间戳
    //设置容器的状态,开还是关
    this.closed.set(false);
    this.active.set(true);

    //这是记录日志方便调试
    if (logger.isDebugEnabled()) {
       if (logger.isTraceEnabled()) {
          logger.trace("Refreshing " + this);
       }
       else {
          logger.debug("Refreshing " + getDisplayName());
       }
    }

    // 初始化环境变量
    initPropertySources();

    // 校验配置项是否存在
    getEnvironment().validateRequiredProperties();

    // 记录事件监听器
    if (this.earlyApplicationListeners == null) {
       this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
    }
    else {
       // 重置本地监听器,回到刷新前的状态
       this.applicationListeners.clear();
       this.applicationListeners.addAll(this.earlyApplicationListeners);
    }

    //初始化 earlyApplicationEvents(存储早期事件)
    this.earlyApplicationEvents = new LinkedHashSet<>();
}

这是Spring容器启动的第一步,确保整个环境、监听器、事件系统都处于正确的状态,这里有几个点需要注意的是:

initProPropertySources()在实际的Spring开发中一般是要在SpringBoot的Configurable ApplicationContext里重写这个方法来自定义配置,另外这是这个占位方法(Hook方法)。

validateRequiredProperties()确保必填属性存在

earlyApplicationListeners&earlyApplicationEvents机制是存储早期事件,后续发布

1.1.2 obtainFreshBeanFactory

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

这段代码就是刷新并获取一个新的BeanFactory,为后续的Bean定义加载与实例化提供基础。refreshBeannFactory这个方法最为关键,负责创建并加载BeanFactory与Bean定义。这一步要把先前的容器和实例都销毁掉。

1.1.3 prepareBeanFactory

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

这一段就是设置Bean的类加载器、表达式解析器、以及资源注册属性编辑器。

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

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.ignoreDependencyInterface(ApplicationStartupAware.class);

这一部分就是注入几个Aware接口,这里注入的ApplicationContextAware用来获取整个Spring应用的上下文,这里要注意的是Aware接口的作用就是回调,Spring容器在创建Bean的时候,将容器的相关资源注入到Bean中去。

后面的代码主要的作用就是注册事件监听器、注册一些可以直接注入的依赖类型、注册一些默认的环境相关Bean、是否开启AOP功能。

1.1.4 postProcessBeanFactory

这是留给子类扩展的钩子方法,可以用来动态修改Bean的定义或者注册新的Bean

1.1.5 invokeBeanFactoryPostProcessors

调用并执行所有已注册的 BeanFactoryPostProcessor 接口实现类,允许你在 Bean 实例化之前修改 Bean 的定义信息。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//委托给其他方法来执行,执行所有的Processor来进行扩展
           PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
		if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null &&
				beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

可以看到这里的这个方法是委托给PostProcessorRegistrationDelegate来做的,它是一个Spring容器初始化阶段的重要扩展入口,Spring会执行所有的BeanFactoryPostProcessor,允许在Bean实例化之前对容器进行深度定制和增强。

1.1.6 registerBeanPostProcessor

这里也是委托给PostProcessorRegistrationDelegate来做的,注册所有的BeanFactoryProcessor到BeanFactory中,供给后续Bean实例化时执行。

1.2 Bean初始化&事件广播

1.2.1 initMessageSource

这个方法的主要功能就是如果你需要在应用中支持多语言,则这个方法会为你提供这个功能:如果你定义了messageSource Bean,则使用这个。如果你没定义的话那就创建默认的DelegatingMessageSource

protected void initMessageSource() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
                //这里就是查看有没有用户自定义
		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
			this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
			if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource hms &&
					hms.getParentMessageSource() == null) {
				// Only set parent context as parent MessageSource if no parent MessageSource
				// registered already.
				hms.setParentMessageSource(getInternalParentMessageSource());
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Using MessageSource [" + this.messageSource + "]");
			}
		}
		else {
			// 使用默认的国际化支持
			DelegatingMessageSource dms = new DelegatingMessageSource();
			dms.setParentMessageSource(getInternalParentMessageSource());
			this.messageSource = dms;
			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
			}
		}
	}

1.2.2 initApplicationEventMulticaster

initApplicationEventMulticaster确保应用内的事件能够被广播并响应;支持用户自定义,也提供默认实现。所谓的事件机制其实就是 发布-订阅模型 这个在很多组件的设计上都有运用,能够让不同组件之间进行解耦通信。

1.2.3 onRefresh

这里也是个钩子方法,是一个空实现,它的存在就是让子类重写它,添加一些特有行为。 实际意义上对于一些web应用,它在此处会初始化Web环境,例如:

  • 初始化DispatcherServlet
  • 初始化WebSocket服务
  • 启动嵌入式Servlet容器(如Tomcat)

总而言之这个方法,onRefresh() 是 Spring 提供给子类的一个生命周期扩展点,用于在容器完成基础初始化之后、所有 Bean 创建之前,执行子类特有的逻辑,默认不做任何操作,子类按需实现。

1.2.4 registerListeners

这个方法主要是注册事件监听器,为Spring的事件机制做好准备。

protected void registerListeners() {
		// 首先注册静态指定的监听器。
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		// 不要在这里初始化 FactoryBeans:我们需要保留所有常规 bean
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

registerListeners() 是将所有的 ApplicationListener 注册到事件广播器的关键步骤,确保后续事件能被正确监听和响应。

1.2.5 finishBeanFactoryInitialization

作用:完成 BeanFactory 的初始化,包括实例化所有剩余的非懒加载单例 Bean。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service if present.
    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 (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early
    String[] weaverAwareBeans = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareBean : weaverAwareBeans) {
        getBean(weaverAwareBean);
    }

    // Stop using the temporary class loader for type matching
    beanFactory.setTempClassLoader(null);

    // Freeze configuration - no more changes to the bean definitions
    beanFactory.freezeConfiguration();

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

整个的流程步骤是:

  • 初始化ConversionService,如果容器里有这个Bean,设置为类型转换器,支持类型自动转换
  • 添加值解析器
  • 提前初始化LoadTimeWeaveAware的Bean,提前创建用于运行期类加载的相关Bean,支持AspectJ等技术
  • 清除临时类加载器
  • 冻结配置:不允许再修改BeanDefinition,防止后续干扰
  • 实例化所有非懒加载单例Bean:这一步很重要!调用preInstantiateSingletons()方法,实例化所有非懒加载的单例Bean,初始化整个容器

实际上触发的事挺多的,调用Bean的构造方法;依赖注入;AOP代理对象的生成等。总而言之构建完成的容器正式具备运行能力。

1.2.6 finishRefresh

这一步就是将容器启动完成,发布事件、清理缓存。

protected void finishRefresh() {
		// Reset common introspection caches in Spring's core infrastructure.
		resetCommonCaches();

		// Clear context-level resource caches (such as ASM metadata from scanning).
		clearResourceCaches();

		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));
	}

refresh()方法的IoC容器启动的入口方法,也是我们理解整个Spring启动原理的关键。整个refresh()方法像一场“开机自检”,12个步骤涵盖了容器准备、配置加载、事件机制、Bean创建与扩展,是理解Spring原理的核心入口!

整个流程是这样

  • prepareRefresh
  • obtainFreshBeanFactory
  • prepareBeanFactory
  • postProcessBeanFactory
  • invokeBeanFactoryPostProcessors
  • registerBeanPostProcessors
  • initMessageSource
  • initApplicationEventMulticaster
  • onRefresh
  • registerListeners
  • finishBeanFactoryInitialization
  • finishRefresh

2. 解析配置并加载BeanDefinition

配置的解析一般有3种方式:XML方式和注解方式或者是配置文件,这里就着重说一下注解方式,我们经常在代码里会碰到这几个注解@Component、@Bean、@Controller、@Service等注册Bean,这一步只是解析配置并注册到BeanFactory的beanDefinitionMap中,还没创建实际的Bean。就像是生产衣服,布料已经准备好了,这里的布料就是beanDefinition

这里参与到的接口是BeanDefinitionReader,这个接口就是加载配置文件的统一接口,由各个加载方式进行实现,如果后期你想要用其他方式进行配置例如JSON,则必须要实现这个接口。

3. 注册核心BeanPostProcessor(AOP/依赖注入关键)

布料和完整的衣服中间其实还有很多其他步骤,则这时候这一步就相当于做了一个加工,这里叫做后置增强器,可以对bean的定义信息进行统一修改,也就是对BeanDefinition对象进行扩展功能,后置增强器有很多个,像AutowiredAnnotationBeanPostProcessorApplicationContextAwareProcessor等,你可以选择实现一个或者多个。

4. 实例化非懒加载的Bean

上面三步我们得到了完整的BeanDefinition,这时候就可以创建对象了,那这里就到了Bean的生命周期部分,也是面试经常会问的一个问题。我们粗略的来看的话bean的生命周期大概分为以下几步:

未命名文件 (5).png

这个过程的源码重点方法是finishBeanFactoryInitialization() 中的beanFactory.preInstantiateSingletons(); 那我们来细致的看一下每一步:

4.1 对象的实例化

所谓的实例化指的是从BeanDefinition -> 转换为一个实际的Java对象,而不仅仅是new一个对象出来就好了,在这个实例化的前后也有几个过程

image.png图片来源:Java架构师

在这里我把实例化后置和属性修改归到依赖注入这一块,则真正的实例化可分为下面2步

前置是第一步,前置这里取到的参数是beanClass和beanName,也就是在实例化之前对bean对象的class信息进行修改,这里BeanPostProcessor本质上是动态代理AOP技术。

实例化是第二步,真正创建对象,目的是根据构造函数创建Bean对象,这一步就是通过反射来创建或者通过Cglib来创建。

4.2 依赖注入

在上一步实例化之后,对象的属性还没有赋值,这里的源码方法为: InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(Object bean, String beanName),在这里有几个要判断的属性都为true的时候才能进行属性注入或者增删改操作。

注入字段、setter、@Autowired、@Value都是在这步完成。这个方法是AbstractAutowireCapableBeanFactory.populateBean(),通过此方法进行赋值。

另外还需要通过一系列的Aware方法去给容器的属性赋值,Aware接口是Spring提供一系列标记接口,主要功能就是让实现这些接口的Bean能够获取Spring容器的特定信息,从而与容器进行交互。比如获取Bean的名称、类加载器、Bean工厂等。这里我举几个例子:

BeanNameAware:用于感知Bean的名称。当Spring实例化一个实现了这个接口的Bean的时候,会回调该接口的setBeanName方法,将Bean的名称传递给它。

BeanClassLoaderAware:用来感知类的加载器变化,在Bean实例化过程中会调用set的这个方法,使Bean能够获取到加载它的类加载器。

等等

4.3 初始化回调

源码方法:initializeBean(beanName, exposedObject, mbd);

初始化实际上就是对完成依赖注入后的Bean再做一系列操作,使其达到“可用状态”的过程。整个源码的过程大概如下:

protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
    // 1. Aware 接口处理
    if (bean instanceof Aware) {
        // 注入 BeanName、BeanFactory、ApplicationContext 等
    }

    // 2. BeanPostProcessor 的 before 初始化
    Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

    // 3. 执行初始化方法
    invokeInitMethods(beanName, wrappedBean, mbd);

    // 4. BeanPostProcessor 的 after 初始化
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

    return wrappedBean;
}

也是分为初始化前置、后置、初始化。我们具体来看这几个步骤:

  • 调用BeanPostProcessor(初始化前):所有实现了BeanPostProcessor的类会在这里被回调,这也是AOPSpringBoot自动配置的增强点
  • 执行Bean的初始化方法:初始化方法有三个,分别是@PostConstruct、InitializingBean.afterPropertiesSet()init-method,这三个方法按顺序调用。

5. 使用

后面使用就没什么好说的了

6. 销毁

首先要知道的是Bean都是默认单例的,如果要设置多例,需要修改元注解@Scope,多例模式也叫原型模式,底层是使用深拷贝来复制一个对象。

对于Spring来说,会主动去管理与销毁的只是单例Bean,容器关闭的时候自动销毁。而多例创建完交给你就不管了。那什么叫原型模式呢?

其实是这样,普通的单例Bean只创建一次,而原型Bean是每次getBean()都会创建一个新的Bean实例。

6.1 单例Bean销毁

单例Bean销毁要先调用DisposableBean.destroy(),然后再去调用destory-method方法。这里源码我不贴了,整个的流程是这样: AbstractApplicationContext#close() → doClose() → destroyBeans() → beanFactory.destroySingletons()

6.2 原型Bean销毁

多例模式下,Spring无法进行管理,所以将生命周期交给用户控制,用户用完bean对象后,java垃圾处理器会自动将无用的对象进行回收操作。

7. 总结

今天这篇文章就写到这里,文章主要把IoC容器的初始化,以及Bean的生命周期都描述了。整个IoC的重点也就在这里了,然后大家在看源码的时候一定要注意,我们日常在扩展的时候在哪些阶段以及对那些方法或者接口操作来达到我们想要的目的。

现在是凌晨1:24,这篇文章也是写了几天,主要是什么都想写但是也不想什么都写。索性就按照我认为的重点来写吧!加油,加油!