Spring源码之bean的实例化createBeanInstance方法解读

本文深入探讨Spring框架中bean实例化的关键方法`createBeanInstance`,涉及通过构造函数、工厂方法等多种方式进行bean实例化。文章通过源码分析,详细解释了方法的执行流程,包括构造函数的选择、参数解析等步骤,帮助读者理解Spring容器内部的工作机制。
摘要由CSDN通过智能技术生成

前言

这篇文章是 IOC 容器初始化启动时,抽象类 AbstractAutowireCapableBeanFactorydoCreateBean() 方法里面的 createBeanInstance() 方法,顾名思义是 bean 的实例化方法

阅读本篇文章,同时可以参考阅读 spring源码之getBean(获取 bean)方法解读(二)Spring Aop代理对象的产生(一) 这两篇文章的 doCreateBean() 方法

示例代码

我们可以使用示例代码进行调试,以便更容易理解源码

Java 实体

public class Student {
   

    private String name;

    public Student() {
   
        System.out.println("Student 的无参构造器被调用了");
    }

    public Student(String name) {
   
        System.out.println("Student 的有参构造器被调用了");
        this.name = name;
    }

    @Override
    public String toString() {
   
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="com.atguigu.pojo.Student">
    	<!--构造函数注入(实体类不需要 set/get 方法)-->
        <constructor-arg value="小明"></constructor-arg>
    </bean>
</beans>

测试类

public class Test2 {
   

    public static void main(String[] args) {
   
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-spring.xml");
        Student student = (Student) applicationContext.getBean("student");
        System.out.println(student.toString());
    }
}

测试结果:
Student 的有参构造器被调用了
Student{
   name='小明'}

createBeanInstance() 方法概述

createBeanInstance() 方法是 spring 实例化 bean 的核心代码,它根据不同的情况会调用四种实例化方法

  • obtainFromSupplier() :通过 Supplier 实例化
  • instantiateUsingFactoryMethod():通过工厂方法实例化
  • autowireConstructor():用合适的构造函数实例化
  • instantiateBean():用无参构造函数实例化
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   
    
	// 确认需要创建的bean实例的类可以实例化
	Class<?> beanClass = resolveBeanClass(mbd, beanName);
	// 确保class不为空,并且访问权限是public
	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());
	}

	/**
	 * ----------1,通过Supplier实例化------------
	 */
	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
   
		return obtainFromSupplier(instanceSupplier, beanName);
	}
    
	/**
	 * ----------2,通过工厂方法实例化------------
	 */
	if (mbd.getFactoryMethodName() != null) {
   
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

    /**
	 * ----------3,用合适的构造函数实例化------------
	 *
	 *  一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器。
	 *  在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,
	 *  避免再次创建相同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);
		}
	}

	// 从bean后置处理器中为自动装配寻找构造方法
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
   
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// 找出最合适的默认构造方法
	ctors = mbd.getPreferredConstructors();
	if (ctors != null) {
   
		// 构造函数自动注入
		return autowireConstructor(beanName, mbd, ctors, null);
	}

    /**
	 * ----------4,使用默认构造函数构造------------
	 */
	return instantiateBean(beanName, mbd);
}

以上源码的执行步骤流程

  • 如果 RootBeanDefinition 中存在 Supplier 接口实例,则使用 Supplier 接口回调来实例化
  • 如果 RootBeanDefinition 中存在 factoryMethodName 属性,或者在配置文件中配置了 factory-method标签,spring 会尝试使用 instantiateUsingFactoryMethod() 方法,根据 RootBeanDefinition 中的配置生成 bean 的实例。如果一个类中的方法被 @Bean 注解修饰,那么 spring 则会将其封装成一个 ConfigurationClassBeanDefinition。此时 factoryMethodName 也被赋值。所以也会调用 instantiateUsingFactoryMethod() 方法通过反射完成方法的调用,并将结果注入 spring 容器中
  • 当以上两种都没有配置时,spring 则打算通过构造函数来实例化 bean。首先会判断是否有缓存,即构造函数是否已经被解析过了, 因为一个 bean 可能会存在多个构造函数,这时候 spring 会根据参数列表的来判断使用哪个构造函数进行实例化。但是判断过程比较消耗性能,所以 spring 将判断好的构造函数缓存到 RootBeanDefinition 中的 resolvedConstructorOrFactoryMethod 属性中
  • 如果缓存,则不需要解析,直接调用 autowireConstructor() 或者 instantiateBean() 方法实例化 bean。有参构造调用 autowireConstructor() 方法,无参构造调用 instantiateBean() 方法
  • 否则需要先进行解析,这里通过 determineConstructorsFromBeanPostProcessors() 方法调用了 SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors() 的后处理器方法来进行解析,spring 默认的实现在AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors() 方法中
  • 获取解析后的候选的构造函数列表 ctors 后(最终的构造函数就从这个列表中选取),开始调用 autowireConstructor() 或者 instantiateBean() 方法实例化 bean。在 autowireConstructor() 方法中,进行了候选构造函数的选举,选择最合适的构造函数来构建 bean,如果缓存已解析的构造函数,则不用选举,直接使用解析好的构造来进行 bean 的实例化

obtainFromSupplier() 通过 Supplier 实例化

Supplier 方式比较简单,在此不再赘述,instanceSupplier.get() 回调到自己定义的函数里面返回一个实例对象然后包装成 BeanWrapperImpl 返回就行了

instantiateUsingFactoryMethod() 通过工厂方法实例化

如果 RootBeanDefinition 类中存在 factoryMethodName 属性,或者在配置文件中配置了 factory-methodfactory-bean 标签,spring 会尝试使用 instantiateUsingFactoryMethod() 方法进行 bean 的实例化

这个源码太长,也并不重要,就不在这里展示了。简单来说,这里可以分为两种情况

  • xml 文件配置中,可以使用 factory-beanfactory-method 两个标签可以指定一个类中的方法,spring 会将这个指定的方法的返回值作为 bean 返回(如果方法是静态方法,则可以不创建 factory-bean 就直接调用,否则需要先将 factory-bean 注入到 spring 容器中)
  • @Bean 注解的解析。在 ConfigurationClassPostProcessor 后处理器中,会对被 @Bean 注解修饰的方法进行解析,生成一个 ConfigurationClassBeanDefinitionBeanDefinition。此时 BeanDefinitionfactoryMethodName 正是 @Bean 修饰的方法本身。所以这里会调用 instantiateUsingFactoryMethod() 方法。通过回调的方式调用 @Bean 修饰的方法,并将返回结果注入到 spring 容器中

通过静态工厂实例化 bean 示例

public class UserFactory {
   
	
	// 静态方法
	public static User getUser1() {
   
		return new User();
	}
}

xml 配置文件

<!-- 使用静态工厂实例化 user -->
<bean id="user1" class
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值