携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第35天,点击查看活动详情
基于 Spring Framework v5.2.6.RELEASE
前情提要
上一篇开始了 Spring 得到 RootBeanDefinition 并初始化依赖的 Bean 实例之后,创建 Bean 实例部分代码的阅读和分析,在getSingleton方法内,Spring 再次尝试了从缓存集合中获取 Bean。在createBean方法中,Spring 处理了方法覆盖相关的内容,并且调用了 InstantiationAwareBeanPostProcessor 中的处理方法,此处也是自定义 Bean 实例创建的扩展点之一。最后,Spring 会在 AbstractAutowireCapableBeanFactory 中的doCreateBean执行默认的实例创建逻辑。本文将从这个方法开始入手。
doCreateBean方法概览
以下是doCreateBean方法的代码:
方法中代码比较多,因此才用了截图的方式。Spring 通过默认方式创建 Bean 实例的过程就都在这个方法里了。我们从上到下逐步分析。
首先看第一部分代码:
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
这里首先会从factoryBeanInstanceCache中获取一个 BeanWrapper 类型的对象,如果获取不到,就通过createBeanInstance方法创建。后半部分的几行代码就是给之后用到的局部变量赋值。这里值得重点关注的是 BeanWrapper 接口和createBeanInstance方法。
BeanWrapper
BeanWrapper 是org.springframework.beans包中的一个重要的接口,比较底层,一般我们基于 Spring 开发项目的时候,不会接触到这个接口。它的作用,就和它的名字一样,是一个 Bean 实例的包装类,并提供了一些对 Bean 实例进行操作的功能,在 Spring 创建 Bean 实例的过程中,需要通过 BeanWrapper 进行一些操作,比如获取和设置属性值等。在之后的代码分析中,还会遇到 BeanWrapper 和它的实现类,到时候可以看看 Spring 通过它具体做了哪些工作。
createBeanInstance 方法
接下来进入createBeanInstance方法。
这个方法的代码量同样不小。
在方法的开头,Spring 获取的即将创建的 Bean 实例的类型信息,并确保能够获取到类型信息、类是public修饰的、并且没有设置可以访问非public的构造器和方法,否则抛出异常。
通过 Supplier 创建 Bean 实例
接下来是从类定义中获取instanceSupplier,这个instanceSupplier是 Supplier 类型的,如果它不是空的话,则调用obtainFromSupplier方法获取一个 BeanWrapper 并返回。
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
也就是说,这个方法是可以返回一个作为结果的 BeanWrapper 实例的。我们进去看一下:
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
String outerBean = this.currentlyCreatedBean.get();
this.currentlyCreatedBean.set(beanName);
try {
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;
}
其实就是通过instanceSupplier的get方法创建一个 Bean 实例,并将其封装到一个 BeanWrapperImpl 中并返回。
不过 BeanDefinition 中的instanceSupplier默认是空的,并且之前我们也没有进行相关的操作,因此这里的创建逻辑不会被执行。
通过工厂方法创建 Bean 实例
再回到createBeanInstance方法,判断完instanceSupplier之后,又判断了 BeanDefinition 中是不是有factoryMethodName。
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
这个factoryMethodName属性,对应的 XML 配置文件中,bean标签的factory-method配置。这个特性在日常工作中几乎用不到,因此之前没有介绍,这里简单说一下。
除了通过实现 FactoryBean 接口来实现一个创建 Bean 的工厂,也可以不实现任何接口,开发一个可以得到特定类型 Bean 的工厂类。但是,需要把工厂类中,能够生产 Bean 实例的方法名称,配置到bean标签的factory-method属性值中。
如果这个方法是一个静态方法,那么可以这样配置:
<bean id="user" class="xxx.UserFactory" factory-method="getUser" />
如果这个方法不是静态方法,则还需要创建一个工厂类的实例,可以这样配置:
<bean id="userFactory" class="xxx.UserFactory" />
<bean id="user" factory-bean="userFactory" factory-method="getUser" />
这部分不常用,大概了解一下就可以,这里也不进行更深入的分析了。
通过反射创建 Bean 实例
再看接下来的一段代码。
// Shortcut when re-creating the same 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);
}
}
因为我们整个流程是从getBean(String name)方法开始分析,args应该是空的,而且 BeanDefinition 的resolvedConstructorOrFactoryMethod属性默认也是空的,因此,这段代码实际上是执行不到的。
不过,我们可以大概分析一下这段逻辑,这里应该是要解决构造方法中参数值自动装配的逻辑,如果需要参数的自动装配,就通过autowireConstructor方法来创建实例,如果不需要,则通过instantiateBean方法调用默认构造方法来创建实例。
接着往下看。
// 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);
}
这里通过determineConstructorsFromBeanPostProcessors方法,获取到了 Bean 的类型中可用的构造函数。具体代码如下:
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors
@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
}
return null;
}
其实就是执行了特定类型的 BeanPostProcessor 的处理逻辑,也就是 SmartInstantiationAwareBeanPostProcessor 中的determineCandidateConstructors方法,它可以用来获取 Bean 的候选构造函数。然后进行判断,如果满足一系列判断条件,则执行autowireConstructor方法创建 BeanWrapper。
从写判断逻辑和autowireConstructor方法名都可以看出,这里跟构造方法的@Autowrired注解有一定关系,不在本文的讨论范围,因此,这里不做过多介绍。感兴趣的话,可以大概浏览一下方法中的逻辑,其实就是根据构造方法的参数列表信息和给定的参数值数组,将这些参数的实例获取到并调用构造方法来创建 Bean 实例,并包装到 BeanWrapper 中返回,主要使用了反射的机制。
回到createBeanInstance方法中接着往下看。
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
这里的getPreferredConstructors默认会返回空。
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
方法的最后,就是没有特殊处理的情况,调用了instantiateBean方法,通过无参构造方法来创建实例。方法的代码如下:
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
这里可以看到,最重要的一行代码就是:
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
接着深入,找到instantiate方法。
// org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
这里通过bd.hasMethodOverrides()判断是不是有方法覆盖。如果有的话,则通过instantiateWithMethodInjection创建结果实例,从方法名和这里的注释可以推测出,方法覆盖注入是通过cglib来实现的。因为这个特性应用得并不多,就不过多介绍了,感兴趣可以跳到方法内部看一下源码,逻辑并不复杂。
下面看if语句块中的部分。这部分的主要逻辑就是获取到当前 Bean 类型的构造器,然后交给 BeanUtils 的instantiateClass方法进行实例的创建。
// org.springframework.beans.BeanUtils#instantiateClass(java.lang.reflect.Constructor<T>, java.lang.Object...)
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return KotlinDelegate.instantiateClass(ctor, args);
}
else {
Class<?>[] parameterTypes = ctor.getParameterTypes();
Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
Object[] argsWithDefaultValues = new Object[args.length];
for (int i = 0 ; i < args.length; i++) {
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
}
else {
argsWithDefaultValues[i] = args[i];
}
}
return ctor.newInstance(argsWithDefaultValues);
}
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
一套标准的反射创建对象的流程,最终,Spring 通过反射机制创建出了 Bean 的实例。
总结
通过本文的分析,终于走到了 Spring 最终把 Bean 实例创建出来的,这个实例会被一个 BeanWrapper 类型的对象包装,并返回到doCreateBean方法中,不过,在doCreateBean方法中,这才只完成了第一步,后面还有更多的处理流程。