目录
前言
这篇文章是 IOC
容器初始化启动时,抽象类 AbstractAutowireCapableBeanFactory
的 doCreateBean()
方法里面的 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-method
或 factory-bean
标签,spring
会尝试使用 instantiateUsingFactoryMethod()
方法进行 bean
的实例化
这个源码太长,也并不重要,就不在这里展示了。简单来说,这里可以分为两种情况
- 在
xml
文件配置中,可以使用factory-bean
和factory-method
两个标签可以指定一个类中的方法,spring
会将这个指定的方法的返回值作为bean
返回(如果方法是静态方法,则可以不创建factory-bean
就直接调用,否则需要先将factory-bean
注入到spring
容器中) - 对
@Bean
注解的解析。在ConfigurationClassPostProcessor
后处理器中,会对被@Bean
注解修饰的方法进行解析,生成一个ConfigurationClassBeanDefinition
的BeanDefinition
。此时BeanDefinition
的factoryMethodName
正是@Bean
修饰的方法本身。所以这里会调用instantiateUsingFactoryMethod()
方法。通过回调的方式调用@Bean
修饰的方法,并将返回结果注入到spring
容器中
通过静态工厂实例化 bean
示例
public class UserFactory {
// 静态方法
public static User getUser1() {
return new User();
}
}
xml
配置文件
<!-- 使用静态工厂实例化 user -->
<bean id="user1" class