Spring之推断构造方法源码

一、 简介

1. 内容回顾

前面分析了Spring的Bean的生命周期的源码,然后分析了依赖注入源码,以及依赖注入的过程中循环依赖Spring的解决方案。在介绍Bean的生命周期中,我们并没有详细介绍Spring底层是如何真正创建Bean的,其实Spring底层创建Bean和我们new一个对象是一样的,也需要使用到构造函数,这篇文章就详细分析这一部分的源码,这样Bean的生命周期的所有相关的源码就几乎分析完了。

2. Spring推断构造方法

Spring推断构造方法的大致流程如下:
在这里插入图片描述

首先创建AService类:

@Component
public class AService {
   
	@Autowired
	BService bService;
	//空构造方法
	public AService(){
   
		System.out.println("AService的无参构造方法");
	}
	//有参构造方法
	public AService(BService bService){
   
		System.out.println("AService的有参构造方法");
		this.bService=bService;
	}

	public void test(){
   
		System.out.println(bService);
	}
}

AService有两个构造方法,一个是无参的构造方法,一个是有参的构造方法

创建BService:

@Component
public class BService {
   
}

然后我们测试一下:

public class Test {
   

	public static void main(String[] args) {
   
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// 获取 BoxService bean
		AService aService = (AService) applicationContext.getBean("AService");
		// 关闭 ApplicationContext
		applicationContext.close();
	}
}

在这里插入图片描述

由输出结果我们可以看出,在创建AService这个Bean时,默认调用了AService的无参数构造方法。现在我们把无参数的构造方法去掉,再次观察结果。

在这里插入图片描述

发现此时Spring调用了有参数的构造方法,此时我们再加入一个CService

@Component
public class CService {
   
}

然后修改AService代码

@Component
public class AService {
   
	@Autowired
	BService bService;
	@Autowired
	CService cService;

	//	//空构造方法
//	public AService(){
   
//		System.out.println("AService的无参构造方法");
//	}
	//有参构造方法
	public AService(BService bService) {
   
		System.out.println("AService的有参构造方法1");
		this.bService = bService;
	}

	//有参构造方法
	public AService(CService cService) {
   
		System.out.println("AService的有参构造方法2");
		this.cService = cService;
	}

	public AService(BService bService, CService cService){
   
		System.out.println("AService的有参构造方法3");
		this.bService=bService;
		this.cService=cService;
	}

	public void test() {
   
		System.out.println(bService);
	}
}

再次测试
在这里插入图片描述

发现直接报错了,说明Spring在多个构造方法中没有推断出到底使用哪一个构造方法。

我们可以在我们需要的构造方法上加一个@Autowired注解告诉Spring我们要使用哪一个构造方法。

@Component
public class AService {
   
	@Autowired
	BService bService;
	@Autowired
	CService cService;

	//	//空构造方法
//	public AService(){
   
//		System.out.println("AService的无参构造方法");
//	}
	//有参构造方法
	public AService(BService bService) {
   
		System.out.println("AService的有参构造方法1");
		this.bService = bService;
	}

	//有参构造方法
	public AService(CService cService) {
   
		System.out.println("AService的有参构造方法2");
		this.cService = cService;
	}

	@Autowired
	public AService(BService bService, CService cService) {
   
		System.out.println("AService的有参构造方法3");
		this.bService = bService;
		this.cService = cService;
	}

	public void test() {
   
		System.out.println(bService);
	}
}

在这里插入图片描述
同时也可以通过getBean方法来指定我们的构造方法,注意此时AService要改为懒加载的,如果不是懒加载AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);就默认将我们的非懒加载的Bean初始化完了,所以下面测试代码会直接报错,所以需要在AService上加一个@Lazy

public class Test {
   

	public static void main(String[] args) {
   
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// 获取 BoxService bean
		AService aService = (AService) applicationContext.getBean("AService",new CService());
		// 关闭 ApplicationContext
		applicationContext.close();
	}
}

在这里插入图片描述
修改AService

public class AService {
   
	@Autowired
	BService bService;
	@Autowired
	CService cService;

	//	//空构造方法
//	public AService(){
   
//		System.out.println("AService的无参构造方法");
//	}
	//有参构造方法
	public AService(BService bService) {
   
		System.out.println("AService的有参构造方法1");
		this.bService = bService;
	}

	//有参构造方法
	public AService(CService cService) {
   
		System.out.println("AService的有参构造方法2");
		this.cService = cService;
	}

	public AService(BService bService, CService cService) {
   
		System.out.println("AService的有参构造方法3");
		this.bService = bService;
		this.cService = cService;
	}

	public void test() {
   
		System.out.println(bService);
	}
}

现在AService并不是一个Bean,我们修改测试类

public class Test {
   

	public static void main(String[] args) {
   
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
		applicationContext.register(AppConfig.class);
		AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
		beanDefinition.setBeanClass(AService.class);
		//指定创建bean时,构造方法的入参值
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new BService());
		applicationContext.registerBeanDefinition("AService",beanDefinition);
		applicationContext.refresh();
		AService aService = (AService) applicationContext.getBean("AService");
		applicationContext.close();
	}
}

上面我们自己定义了一个BeanDefinition,然后注册到容器中,同样最后也可以拿到创建好的Bean

在这里插入图片描述
下面对上面内容总结一下:

  • 默认情况使用空构造方法,或使用唯一的那一个有参的构造方法
  • 如果指定了构造方法的入参值,通过getBean方法或者BeanDefinition.getConstructorArgumentValues()指定,那就用所匹配的构造方法
  • 如果要Spring自己选定构造方法以及构造方法的入参值,使用autowired="constructor
  • 通过@Autowired注解指定了某个构造方法,但是值Spring自动来找

注意加@Autowired在构造方法或配置autowired="constructor"在xml配置文件中,这两个是有区别的,前者会指定要用那个构造方法(这个是定死的),然后spring自动找对应的参数值,后者构造方法和参数值都是Spring自己去确定的(默认是选参数最多的构造方法)。

上面介绍了多种指定创建Bean时指定构造方法的多种方式,下面我们就针对这些方式详细分析一下Spring底层时怎么做的。

二、 源码分析

上面内容都是创建Bean的内容,所以我们先进入doCreateBean方法。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
   

		// 实例化bean
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
   
			// 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来了(比如依赖注入过程中)
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
   
			// 创建Bean实例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
   
			mbd.resolvedTargetType = beanType;
		}

		// 后置处理合并后的BeanDefinition
		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
   
			if (!mbd.postProcessed) {
   
				try {
   
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
   
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// 为了解决循环依赖提前缓存单例创建工厂
		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
   
			if (logger.isTraceEnabled()) {
   
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 循环依赖-添加到三级缓存
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
   
			// 属性填充
			populateBean(beanName, mbd, instanceWrapper);

			// 初始化
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
   
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
   
				throw (BeanCreationException) ex;
			}
			else {
   
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
   
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
   
				if (exposedObject == bean) {
   
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
   
					// beanName被哪些bean依赖了,现在发现beanName所对应的bean对象发生了改变,那么则会报错
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
   
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
   
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
   
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值