Spring Ioc源码分析系列--容器实例化Bean的四种方法

本文深入分析了Spring Ioc容器实例化Bean的四种方法:使用Supplier、工厂方法(包括从缓存获取参数、解析获取工厂方法和参数)、有参构造函数和默认构造函数。详述了每种方法的实现逻辑,特别是工厂方法和构造函数的参数匹配及权重计算。适合对Spring源码感兴趣的后端开发者阅读。
摘要由CSDN通过智能技术生成

🚀 优质资源分享 🚀

学习路线指引(点击解锁) 知识定位 人群定位
🧡 Python实战微信订餐小程序 🧡 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

Spring Ioc源码分析系列–实例化Bean的几种方法

前言

前面的文章Spring Ioc源码分析系列–Bean实例化过程(二)在讲解到bean真正通过那些方式实例化出来的时候,并没有继续分析了,而是留到了这里去分析,主要是因为获取获取构造函数,推断构造函数也是一个比较复杂的操作,就想另起一篇文章再说,但是总的来说,应该不会比前面的逻辑绕,因为这里很清晰,就是实例化对象的几种方法,那么实例化对象有哪几种选择呢?没印象,那说明前面的文章没留下影响,回去翻翻。所以废话少说,跟着上面文章的口子,我们来分析实例化bean的过程。

源码分析

首先,这里回忆一下之前说到什么。

本篇文章的核心逻辑入口是在AbstractAutowireCapableBeanFactory#createBeanInstance()方法里。
跟进createBeanInstance(beanName, mbd, args)方法。这个方法干了哪几件事?

  • 首先尝试调用obtainFromSupplier()实例化bean
  • 尝试调用instantiateUsingFactoryMethod()实例化bean
  • 根据给定参数推断构造函数实例化bean
  • 以上均无,则使用默认构造函数实例化bean

先贴一下代码,然后逐个分析。

	/**
 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
 * factory method, constructor autowiring, or simple instantiation.
 *
 * 使用适当的实例化策略为指定的 bean 创建一个新实例:工厂方法、构造函数自动装配或简单实例化。
 *
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param args explicit arguments to use for constructor or factory method invocation
 * @return a BeanWrapper for the new instance
 * @see #obtainFromSupplier
 * @see #instantiateUsingFactoryMethod
 * @see #autowireConstructor
 * @see #instantiateBean
 */
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		// 确保此时实际解析了 bean 类。
		Class beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}
		// 通过bd中提供的instanceSupplier来获取一个对象
		// 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
		Supplier instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		//如果工厂方法不为null,则使用工厂方法初始化策略
		// bd中提供了factoryMethodName属性,那么要使用工厂方法的方式来创建对象,
		// 工厂方法又会区分静态工厂方法跟实例工厂方法
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		// 在原型模式下,如果已经创建过一次这个Bean了,那么就不需要再次推断构造函数了
		// 是否推断过构造函数
		boolean resolved = false;
		// 构造函数是否需要进行注入
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				//一个类里面有多个构造函数,每个构造函数都有不同的参数,所以调用前需要根据参数锁定要调用的构造函数或工厂方法
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		//如果已经解析过则使用解析好的构造函数方法,不需要再次锁定
		if (resolved) {
			if (autowireNecessary) {
				//构造函数自动注入
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				//使用默认构造函数进行构造
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		//需要根据参数解析构造函数
		Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			//构造函数自动注入
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		// 默认构造的首选构造函数?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		//使用默认构造函数
		return instantiateBean(beanName, mbd);
	}


使用Supplier实例化bean

这一块的逻辑对应如下

		// 通过bd中提供的instanceSupplier来获取一个对象
		// 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
		Supplier instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

Supplier在Spring里面的使用是相对比较新的,看了一个代码的commit记录,这一块的代码是在2016年12月19号加上的,相对来说还是比较新的。

Supplier就是一个Java 8提供的函数式编程接口,里面提供一个get()方法,可以通过这个方法实例化bean对象。

@FunctionalInterface
public interface Supplier {

 /**
 * Gets a result.
 *
 * @return a result
 */
 T get();
}

跟进obtainFromSupplier()方法,可以看到逻辑是比较简单的,通过一个NamedThreadLocal设置依赖关系beanName,然后调用instanceSupplier.get()获取对象,随后包装成一个BeanWrapper返回。

	/**
 * Obtain a bean instance from the given supplier.
 *
 * 从给定的 supplier 处获取一个 bean 实例。
 *
 * @param instanceSupplier the configured supplier
 * @param beanName the corresponding bean name
 * @return a BeanWrapper for the new instance
 * @since 5.0
 * @see #getObjectForBeanInstance
 */
	protected BeanWrapper obtainFromSupplier(Supplier instanceSupplier, String beanName) {
		Object instance;

		// 这里是处理 Supplier 创建的 bean 的内外部名称依赖关系
		String outerBean = this.currentlyCreatedBean.get();
		this.currentlyCreatedBean.set(beanName);
		try {
			// 调用 get() 方法获取对象
			instance = instanceSupplier.get();
		}
		finally {
			if (outerBean != null) {
				this.currentlyCreatedBean.set(outerBean);
			}
			else {
				this.currentlyCreatedBean.remove();
			}
		}

		if (instance == null) {
			instance = new NullBean();
		}
		BeanWrapper bw = new BeanWrapperImpl(instance);
		initBeanWrapper(bw);
		return bw;
	}

使用工厂方法实例化bean

简介

这一块的代码逻辑对应如下

		//如果工厂方法不为null,则使用工厂方法初始化策略
		// bd中提供了factoryMethodName属性,那么要使用工厂方法的方式来创建对象,
		// 工厂方法又会区分静态工厂方法跟实例工厂方法
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

跟进instantiateUsingFactoryMethod()方法,可以看到这里先new了一个ConstructorResolver,这个ConstructorResolver非常重要,它会去推断合适的构造函数。实例化bean另起这篇文章来写,很大程度就是因为这个ConstructorResolver,我想写清楚一点。

	/**
 * Instantiate the bean using a named factory method. The method may be static, if the
 * mbd parameter specifies a class, rather than a factoryBean, or an instance variable
 * on a factory object itself configured using Dependency Injection.
 *
 * 使用命名工厂方法实例化 bean。
 * 如果 mbd 参数指定一个类,而不是 factoryBean,或者使用依赖注入配置的工厂对象本身的实例变量,则该方法可能是静态的。
 *
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param explicitArgs argument values passed in programmatically via the getBean method,
 * or {@code null} if none (-> use constructor argument values from bean definition)
 * @return a BeanWrapper for the new instance
 * @see #getBean(String, Object[])
 */
	protected BeanWrapper instantiateUsingFactoryMethod(
 String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

		return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
	}

首先来看一下ConstructorResolver类上的定义,翻译一下就是:用于解析构造函数和工厂方法的委托,通过参数匹配执行构造函数解析。

Delegate for resolving constructors and factory methods.Performs constructor resolution through argument matching.

这个类的作用非常强大,可以解析实例化对象的所需的构造器,如果有多个,会根据构造器的参数类型和给定的参数类型通过计算权重的方式去匹配一个最佳的构造器。

跟进方法instantiateUsingFactoryMethod()代码,这个方法整整三百行,可以说非常离谱。

这里先贴个图,看下基本的逻辑。其实逻辑也跟我们写业务差不多,先做些基础准备,这里就是初始化个BeanWrapperImpl,给工厂bean属性赋赋值等,然后就去缓存去工厂方法和参数,取不到就去解析获取方法和参数,然后利用工厂方法和参数,实例化一个对象返回,逻辑清晰。

下面分段来看一下代码吧。

基础属性赋值

这一块代码比较简单,就是初始化一个BeanWrapperImpl,然后给一些属性赋值。

		// 创建并初始化一个 BeanWrapperImpl
		BeanWrapperImpl bw = new BeanWrapperImpl();
		this.beanFactory.initBeanWrapper(bw);

		// 实例化这个Bean的工厂Bean
		Object factoryBean;
		// 工厂Bean的Class
		Class factoryClass;
		// 静态工厂方法或者是实例化工厂方法
		boolean isStatic;

		/*下面这段代码就是为上面申明的这三个属性赋值*/
		String factoryBeanName = mbd.getFactoryBeanName();
		if (factoryBeanName != null) {
			// 如果创建这个Bean的工厂就是这个Bean本身的话,那么直接抛出异常
			if (factoryBeanName.equals(beanName)) {
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"factory-bean reference points back to the same bean definition");
			}
			// 得到创建这个Bean的工厂Bean
			factoryBean = this.beanFactory.getBean(factoryBeanName);
			if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
				throw new ImplicitlyAppearedSingletonException();
			}
			factoryClass = factoryBean.getClass();
			isStatic = false;
		}
		else {
			// It's a static factory method on the bean class.
			// factoryBeanName为null,说明是通过静态工厂方法来实例化Bean的
			// 静态工厂进行实例化Bean,beanClass属性必须要是工厂的class,如果为空,直接报错
			if (!mbd.hasBeanClass()) {
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"bean definition declares neither a bean class nor a factory-bean reference");
			}
			factoryBean = null;
			factoryClass = mbd.getBeanClass();
			isStatic = true;
		}

从缓存获取参数

完成准备后,接下来是从缓存中获取工厂方法和参数,这里也比

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值