Spring源码系列(十五)Spring创建Bean的过程(五)

1.写在前面

前面几篇博客介绍Spring实例化的Bean的过程,各种情况都讲了一边,还剩最后一点点没有讲,今天笔者打算讲完,如果篇幅够得的话,笔者打算对实例化Bean的来个总结。废话不多说,直接上代码。

2.Spring实例化Bean的过程

上篇博客笔者主要讲了推断构造方法后,然后对四个条件进行判断,如果有一个条件成立的话,就会执行autowireConstructor(beanName, mbd, ctors, args);方法,今天笔者继续来讲createBeanInstance()方法,继续看下原来的代码:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	// Make sure bean class is actually resolved at this point.
    // 获取Bean的Class,这儿获取的A.Class,因为笔者条件断点的是a
	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());
	}

    //获取供给型的接口,直接创建Bean
	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
		return obtainFromSupplier(instanceSupplier, beanName);
	}

    //通过工厂方法推断构造函数,同时创建对应的对象
	if (mbd.getFactoryMethodName() != null) {
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// Shortcut when re-creating the same bean...
	boolean resolved = false;
	boolean autowireNecessary = false;
    //这个参数一般的情况都是为空
	if (args == null) {
		synchronized (mbd.constructorArgumentLock) {
            // 这个参数只有在@Bean注解的方法的时候创建RootBeanDefinition的才会这个参数赋值,而@Bean注解的方法在上面
            // instantiateUsingFactoryMethod(beanName, mbd, args);已经创建完成返回了。
            // 所以这个判断只有在创建RootBeanDefinition的时候,同时它的工厂方法名为空,然后这个解析的工厂方法名不为空的时候,才会进入这个判断
            // 已经缓存的构造函数
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
				resolved = true;
                 // constructorArgumentsResolved默认为false
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
    //只有上面判断执行,这个判断才会执行,一般情况下不会执行
	if (resolved) {
		if (autowireNecessary) {
            //通过自动装配的构造函数方式实例化Bean
			return autowireConstructor(beanName, mbd, null, null);
		}
		else {
            //实例化Bean
			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);
}

当我们发现上面条件都不满足的情况,Spring回调用getPreferredConstructors();方法来再查看一下构造函数,当我们打开对应的方法的时候,具体的代码如下:

@Nullable
public Constructor<?>[] getPreferredConstructors() {
	return null;
}

所以这个方法的返回值是空,于是就直接会执行instantiateBean(beanName, mbd);方法,而能执行这个方法的,只有两种情况,一种是只提供默认的无参的构造函数,一种是提供多个构造函数没有加@Autowired注解,这个时候会执行instantiateBean(beanName, mbd);方法。具体为什么只有这两种情况,可以参考笔者之前的博客,其中有详细的介绍。这个时候我们只需要看下 instantiateBean(beanName, mbd);的代码,具体的代码如下:

/**
	 * Instantiate the given bean using its default constructor.
	 * @param beanName the name of the bean
	 * @param mbd the bean definition for the bean
	 * @return a BeanWrapper for the new instance
	 */
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged(
						(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
						getAccessControlContext());
			}
			else {
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}

可以看到方法上的注释 Instantiate the given bean using its default constructor.这句话的意思就是:使用其默认构造函数实例化给定的bean,所以上面的两种情况,只有第一种的情况能创建Bean,我们可以测试下,具体的测试代码如下:

package com.ys.beanLife.bean;

import org.springframework.stereotype.Component;

@Component
public class A{
    public A() {
        System.out.println("A init");
    }
}

运行结果如下:

在这里插入图片描述

可以看到上面的没有报错。如果我们把代码改成如下的:

package com.ys.beanLife.bean;

import org.springframework.stereotype.Component;

@Component
public class A{
    public A(B b) {
        System.out.println("A b init");
    }

    public A(C c) {
        System.out.println("A c init");
    }
}

运行结果如下:

在这里插入图片描述

可以发现直接报错,如果给这个类中添加一个无参的构造函数,是不是就不会报错了,具体的代码如下:

package com.ys.beanLife.bean;

import org.springframework.stereotype.Component;

@Component
public class A{

    public A() {
        System.out.println("A init");
    }

    public A(B b) {
        System.out.println("A b init");
    }

    public A(C c) {
        System.out.println("A c init");
    }
}

运行的结果如下:

在这里插入图片描述

总结:所以前面的条件如果都不满足的话,那么这个Bean必须要提供一个无参的构造函数。不然这个类直接创建不出来。到此这个这个spring实例化的就讲完了,但是这个bean的属性还没有填充,这就是后面讲的。下面就应该总结了。

3.总结

由于内容过多,笔者这儿就直接上一个图,具体的图如下:

在这里插入图片描述

4.写在最后

至此整个Spring创建Bean的实例对象对象就讲完了,这个时候创建的出来的Bean只是一个普普通通的Bean,并没有填充属性,后面的博客会继续讲填充属性的过程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值