Spring源码二十:Bean实例化流程三

上一篇Spring源码十九:Bean实例化流程二中,我们主要讨论了单例Bean创建对象的主要方法getSingleton了解到了他的核心流程无非是:通过一个简单工厂的getObject方法来实例化bean,当然spring在实例化前后提供了扩展如:beforeSingletonCreation与afterSingletonCreate,同样为了提供性能会将实例化后的单例bean放入缓存中;又因为spring设计之初存在三级缓存,所以在放入缓存的时候又会将其他两次的缓存清除。

简单的回忆了之前的内容,我们发现还有一个很重要的点我们没有说到那就是怎么通过简单工厂来创建实例对象的,这一篇咱们详细讨论一下:


createBean

	/**
	 * Central method of this class: creates a bean instance, 创建bean实例对象
	 * populates the bean instance, applies post-processors, etc. 填充bean实例、应用后置处理器
	 * @see #doCreateBean
	 */
	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		// 判断需要创建的bean是否可以实例化、是否可以通过当前类加载器加载
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		// 准备bean中的方法覆盖
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 给BeanPostProcessors一个返回代理而不是目标bean实例的机会。
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			// 如果bean配置类后置处理器PostProcessor,则这里返回一个proxy代理对象
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			// bean实例对象创建方法
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

因为lockup-method属性与repliace-methon配置属性,现在基本上没有使用场景,而resolveBeanClass与preprareMethodOverrides是为了是实现这个两个方法而生的,所以我们直接来看 resolveBeforeInstantiation方法。

resolveBeforeInstantiation


	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					// BeanPostProcessor前置处理方法
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						// BeanPostProcessor后置处理方法
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

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;
	}

InstantiationAwareBeanPostProcessorBeanPostProcessor 的一个子接口,提供了以下方法,用于在 Bean 实例化的不同阶段进行干预:

  • postProcessBeforeInstantiation(Class<?> beanClass, String beanName): 在 Bean 实例化之前调用。
  • postProcessAfterInstantiation(Object bean, String beanName): 在 Bean 实例化之后调用。
  • postProcessProperties(PropertyValues pvs, Object bean, String beanName): 在 Bean 的属性设置之前调用。

这些方法提供了在 Bean 实例化过程中进行自定义逻辑处理的机会,可以用于 Bean 的替换、属性的预处理等操作。

示例代码:

public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        if ("myBean".equals(beanName)) {
            System.out.println("Before instantiation of " + beanName);
            // 可以返回一个代理对象或自定义的 Bean 实例
        }
        return null; // 返回 null 表示继续默认的实例化过程
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) {
        System.out.println("After instantiation of " + beanName);
        return true; // 返回 true 表示继续进行属性设置
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        System.out.println("Processing properties for " + beanName);
        return pvs; // 可以修改属性值
    }
}

InstantiationAwareBeanPostProcessor 扩展了 BeanPostProcessor 的功能,提供了在 Bean 实例化的不同阶段进行干预的能力。通过实现 InstantiationAwareBeanPostProcessor 接口,开发人员可以在 Bean 实例化过程中插入自定义逻辑,实现更灵活的 Bean 管理和控制。

实例化与初始化

为了更好地理解 BeanPostProcessorInstantiationAwareBeanPostProcessor 的区别,我们需要明确实例化和初始化的概念。

  • 实例化:实例化是从零到一创建一个 Bean 的过程,即通过调用构造函数生成 Bean 的实例。
  • 初始化:初始化是在 Bean 实例化之后进行的配置过程,包括属性注入、调用初始化方法等。

在 Spring 容器中,Bean 的生命周期大致分为以下几个阶段:

  1. 实例化:通过调用构造函数创建 Bean 实例。
  2. 属性注入:将依赖的属性注入到 Bean 中。
  3. 初始化:调用自定义的初始化方法,进行额外的配置。

BeanPostProcessor 与 InstantiationAwareBeanPostProcessor 的区别

  • 作用阶段

    • BeanPostProcessor 主要作用于初始化阶段,即在 Bean 的属性已经注入之后进行处理。
    • InstantiationAwareBeanPostProcessor 作用于实例化阶段和属性注入阶段,允许在 Bean 实例化之前、之后以及属性注入之前进行处理。
  • 用途

    • BeanPostProcessor 常用于在 Bean 初始化之前和之后执行一些通用的处理逻辑,如代理增强、配置验证等。
    • InstantiationAwareBeanPostProcessor 常用于在 Bean 实例化过程中执行一些特殊的处理逻辑,如提前终止 Bean 创建、动态生成代理对象、修改属性注入逻辑等。

这个方法是在 Bean 初始化后应用所有注册的 BeanPostProcessorpostProcessAfterInitialization 方法,其设计和实现反映了 Spring 框架中依赖注入和面向切面编程的核心理念。

Spring Bean 生命周期管理

在 Spring 框架中,Bean 的生命周期经历了多个阶段,包括实例化、依赖注入、初始化和销毁等。applyBeanPostProcessorsAfterInitialization 方法所处的阶段是在 Bean 初始化之后,即在所有属性被设置后,执行自定义的后处理逻辑。

BeanPostProcessor 接口作用

BeanPostProcessor 接口定义了在 Bean 初始化前后可以插入自定义逻辑的能力。Spring 容器在创建 Bean 的过程中,会检查是否注册了 BeanPostProcessor,如果有,则会在相应的阶段调用其方法。其中,postProcessAfterInitialization 方法是在 Bean 初始化完成后被调用的,允许开发者对 Bean 进行额外的处理或修改。

applyBeanPostProcessorsAfterInitialization 方法分析

  1. 初始化结果对象:方法开始时,首先将 result 对象初始化为 existingBean,即当前的 Bean 实例。这个 existingBean 是在容器中已经完成初始化的对象。

  2. 遍历处理器列表:方法接着遍历所有注册的 BeanPostProcessor,对每一个后处理器调用其 postProcessAfterInitialization 方法。

    • 每个处理器可以在方法内部执行任何与 Bean 相关的操作,例如添加代理、执行验证、修改属性等。
    • 如果某个处理器返回 null,则表示不需要进一步处理,直接返回当前的 result 对象。
  3. 返回处理后的结果:最终返回经过所有后处理器处理后的 result 对象。这个对象可能是原始的 existingBean,也可能是经过多个处理器处理后的新对象。

技术原理分析

  • 面向切面编程(AOP)的应用:通过 BeanPostProcessor 接口,Spring 实现了 AOP 的一种简单形式。开发者可以在 Bean 初始化后插入切面逻辑,例如添加事务、日志等。

  • 依赖注入的增强:允许在 Bean 初始化后对依赖关系进行增强或修改,以适应不同的运行时需求。

  • 灵活性与可扩展性:applyBeanPostProcessorsAfterInitialization 方法展示了 Spring 框架在管理 Bean 生命周期时的高度灵活性和可扩展性。开发者可以通过注册自定义的 BeanPostProcessor 实现特定的业务逻辑,而不必修改现有的 Bean 实现代码。

applyBeanPostProcessorsAfterInitialization 方法在 Spring 框架中扮演了重要角色,通过它,开发者可以在 Bean 初始化完成后添加自定义逻辑,扩展和定制应用程序的行为。理解这个方法的工作原理和技术实现,有助于深入理解 Spring 容器的工作机制,提升对 Bean 生命周期管理的控制和应用开发的灵活性。

总结

相关推荐

  1. Spring四:Bean流程探讨

    2024-07-10 19:18:01       18 阅读
  2. mini-spring-Bean含参实例

    2024-07-10 19:18:01       43 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 19:18:01       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 19:18:01       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 19:18:01       45 阅读
  4. Python语言-面向对象

    2024-07-10 19:18:01       55 阅读

热门阅读

  1. 学习数据库的增删改查

    2024-07-10 19:18:01       17 阅读
  2. oracle 数据更新procedure 模板

    2024-07-10 19:18:01       20 阅读
  3. 【LeetCode 0050】【分治/递归】求x的n次方

    2024-07-10 19:18:01       20 阅读
  4. Qt图形编辑类使用总结—正在编辑中

    2024-07-10 19:18:01       12 阅读
  5. Spring Boot与Apache Kafka Streams的集成

    2024-07-10 19:18:01       19 阅读
  6. uniapp 封装瀑布流组件

    2024-07-10 19:18:01       20 阅读