Spring 中的 initializeBean 方法的内部逻辑小总结

Spring 中的 initializeBean 方法的内部逻辑小总结

背景

spring-beans 模块中的 AbstractAutowireCapableBeanFactory.java 文件里有 initializeBean 方法,这个方法会负责 beaninitialization(初始化),本文会对其主要逻辑进行总结。

正文

该方法的代码复制如下 ⬇️

java 复制代码
	/**
	 * Initialize the given bean instance, applying factory callbacks
	 * as well as init methods and bean post processors.
	 * <p>Called from {@link #createBean} for traditionally defined beans,
	 * and from {@link #initializeBean} for existing bean instances.
	 * @param beanName the bean name in the factory (for debugging purposes)
	 * @param bean the new bean instance we may need to initialize
	 * @param mbd the bean definition that the bean was created with
	 * (can also be {@code null}, if given an existing bean instance)
	 * @return the initialized bean instance (potentially wrapped)
	 * @see BeanNameAware
	 * @see BeanClassLoaderAware
	 * @see BeanFactoryAware
	 * @see #applyBeanPostProcessorsBeforeInitialization
	 * @see #invokeInitMethods
	 * @see #applyBeanPostProcessorsAfterInitialization
	 */
	@SuppressWarnings("deprecation")
	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		// Skip initialization of a NullBean
		if (bean.getClass() == NullBean.class) {
			return bean;
		}

		invokeAwareMethods(beanName, bean);

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

其中的主要逻辑共有 4 步,可以简单概括如下

主要步骤 做了什么 核心代码
Step 1: (Aware) 处理与 3XXXAware 接口 invokeAwareMethods(beanName, bean);
Step 2: (Before) 尝试在 initialization 之前 做点事情 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
Step 3: (Init) initialization(初始化) invokeInitMethods(beanName, wrappedBean, mbd);
Step 4: (After) 尝试在 initialization 之后 做点事情 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

为了便于查看,我把 4 个步骤的位置在下图中标出来了 ⬇️

Step 1: (Aware)

invokeAwareMethods(String, Object) 方法的代码复制如下 ⬇️

java 复制代码
	private void invokeAwareMethods(String beanName, Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware beanNameAware) {
				beanNameAware.setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					beanClassLoaderAware.setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware beanFactoryAware) {
				beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

如果当前的 bean implement 了以下 3XXXAware 接口中的任意一个,在 invokeAwareMethods(String, Object) 方法中就会进行相应处理。

XXXAware 接口 例子
BeanNameAware 假设一个 bean <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B 需要感知自身的 beanName,我们可以让 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B implement BeanNameAware 接口,那么在 invokeAwareMethods(String, Object) 方法中就会用 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B 来调用 setBeanName(...) 方法,从而将对应的 beanName 填进去
BeanClassLoaderAware
BeanFactoryAware 假设一个 bean <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B 需要感知 BeanFactory,我们可以让 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B implement BeanFactoryAware 接口,那么在 invokeAwareMethods(String, Object) 方法中就会用 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B 来调用 setBeanFactory(...) 方法,从而将 BeanFactory 填进去

Step 2: (Before)

applyBeanPostProcessorsBeforeInitialization(Object, String) 方法的代码复制如下 ⬇️

java 复制代码
	@Deprecated(since = "6.1")
	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

这里的逻辑是遍历所有的 BeanPostProcessor,依次调用它们的 postProcessBeforeInitialization 方法(可能会提前结束)

例如我们平时用的 @PostConstruct 注解,它对应的 BeanPostProcessorCommonAnnotationBeanPostProcessor。而对 @PostConstruct 的支持,就体现在 Step 2 里(可以打断点进行验证,这里就不展开说了)。

Step 3: (Init)

invokeInitMethods(String, Object, RootBeanDefinition) 方法的代码复制如下 ⬇️

java 复制代码
	/**
	 * Give a bean a chance to initialize itself after all its properties are set,
	 * and a chance to know about its owning bean factory (this object).
	 * <p>This means checking whether the bean implements {@link InitializingBean}
	 * or defines any custom init methods, and invoking the necessary callback(s)
	 * if it does.
	 * @param beanName the bean name in the factory (for debugging purposes)
	 * @param bean the new bean instance we may need to initialize
	 * @param mbd the merged bean definition that the bean was created with
	 * (can also be {@code null}, if given an existing bean instance)
	 * @throws Throwable if thrown by init methods or by the invocation process
	 * @see #invokeCustomInitMethod
	 */
	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
			}
			((InitializingBean) bean).afterPropertiesSet();
		}

		if (mbd != null && bean.getClass() != NullBean.class) {
			String[] initMethodNames = mbd.getInitMethodNames();
			if (initMethodNames != null) {
				for (String initMethodName : initMethodNames) {
					if (StringUtils.hasLength(initMethodName) &&
							!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
							!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
						invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
					}
				}
			}
		}
	}

这个方法会处理以下 2 种情况

  • 如果当前 bean <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B implementInitializingBean 接口,则尝试通过 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B 来调用 InitializingBean 接口中的 afterPropertiesSet() 方法
  • 如果当前 bean <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B 指定了 init method(例如可以在 xml 文件里指定 init method),则尝试通过 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B 来调用这些 init method

Step 4: (After)

applyBeanPostProcessorsAfterInitialization(Object, String) 方法的代码复制如下 ⬇️

java 复制代码
	@Deprecated(since = "6.1")
	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

这一步和 Step 2 的代码类似,其逻辑是遍历所有的 BeanPostProcessor,依次调用它们的 postProcessAfterInitialization 方法(可能会提前结束)

相关推荐
麦兜*2 天前
MongoDB Atlas 云数据库实战:从零搭建全球多节点集群
java·数据库·spring boot·mongodb·spring·spring cloud
麦兜*2 天前
MongoDB 在物联网(IoT)中的应用:海量时序数据处理方案
java·数据库·spring boot·物联网·mongodb·spring
青衫客362 天前
Spring异步编程- 浅谈 Reactor 核心操作符
java·spring·响应式编程
Cyan_RA92 天前
SpringMVC @RequestMapping的使用演示和细节 详解
java·开发语言·后端·spring·mvc·ssm·springmvc
wuxuanok3 天前
SpringBoot -原理篇
java·spring boot·spring
若鱼19193 天前
spring-kafka消费异常处理
spring·kafka
送秋三十五3 天前
spring源码分析————ListableBeanFactory
java·后端·spring
一又四分之一.3 天前
spring、springboot、springCloud
spring boot·spring·spring cloud
float_六七3 天前
Spring事务注解@Transactional核心机制详解
java·后端·spring