hexon
发布于 2026-02-12 / 4 阅读
0

11、推断构造方法底层源码解析

在之前的文章中,我们详细分析了Spring依赖注入的执行流程。然而,在依赖注入发生之前,Bean的实例化过程需要首先确定使用哪个构造方法来完成对象的创建。这一关键步骤通常被称为构造方法推断。虽然我们在前面的内容中简要提及了这一机制,但并未深入其实现细节。本文将聚焦于Spring是如何在多个构造方法中做出选择的。我们将先通过具体示例阐明构造方法推断的实际行为与意义,再逐步深入到源码层面,解析其内部的判断逻辑与执行流程。

构造器注入本身就是依赖注入的一种实现方式。在上一节的分析中,我们主要探讨了字段注入Setter方法注入等依赖注入的具体形式,而关于构造器注入这一更为核心的机制——特别是Spring如何选择合适的构造方法来实例化Bean——我们并未展开深入分析。

推断构造方法具体的源码位置是在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean中调用的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance方法中体现的。

createBeanInstance方法中还有@Bean的处理,@Bean的处理后面有单独的文章分析。

本文内容:

  1. 什么是Spring中的推断构造方法?

  2. @Autowired注解推断构造方法底层源码解析

  3. 构造方法注入底层源码解析

  4. Spring自动推断构造方法底层源码解析

  5. 严格模式和宽松模型底层源码解析

  6. RuntimeBeanReference底层源码解析

  7. 构造方法排序逻辑底层源码解析

推断构造方法常见应用场景

当前,Spring官方推荐使用构造方法注入的方式进行依赖注入。然而,在实际工作中,许多开发者对此使用得并不多,对其工作机制也较为陌生。因此,在深入源码之前,我们有必要先理解构造方法推断在实际使用中扮演的角色及其常见应用场景。

思考下面的代码:

@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

在UserService中有三个构造方法,那么Spring在创建UserService的实例的时候会用哪一个构造方法呢?另外,我们前面还提到了可以将@Autowired注解加在构造器上,又是什么情况呢?Spring中这一部分的处理逻辑就称为推断构造方法。

假如我们把@Autowired注解标注在2个参数的构造器:

@Autowired
public UserService(OrderService orderService, OrderService orderService1) {
    this.orderService = orderService;
    System.out.println(2);
}

Spring推断出使用这个构造方法就会来调用,这个里面的关键就是找到构造方法的两个参数传进来,可能就是根据第1个参数的类型查找再根据名称查找,根据第2个参数的类型查找,再根据名称查找。这个依赖查找的过程,在上篇文章中我们是详细分析过的。

在分析源码前,我们先具体看下其它常见的构造方法注入的应用场景。

@ComponentScan
public class MyConfig {

}
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		UserService userService = applicationContext.getBean("userService", UserService.class);
		userService.test();
	}
}
public class OrderService {


}

未显式定义构造方法

@Component
public class UserService {

	private OrderService orderService;

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

}

结果:不会报错,但是不会给orderService赋值,默认是调用了编译器追加的默认构造方法。

多个构造方法,但存在一个默认构造方法

@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

结果:不会报错,会打印0和null(调用无参数构造方法),但是不会给orderService赋值。

单且仅当只有一个构造方法

@Component
public class UserService {

	private OrderService orderService;

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

直接执行会报错,需要给OrderService加上@Component注解才能正常执行。

@Component
public class OrderService {

}

执行结果:

2
com.hexon.service.OrderService@1cbbffcd

这个情况是因为两个参数Spring都能找到对应的Bean,所以能成功调用2个参数的构造方法。当然下面的这种也是一样的:

@Component
public class UserService {

	private OrderService orderService;

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

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

}

执行结果:

1
com.hexon.service.OrderService@72f926e6

多个构造方法,但不存在默认构造方法

@Component
public class UserService {

	private OrderService orderService;

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

执行结果:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.hexon.service.UserService]: No default constructor found

这个地方,相当于Spring内部它发现有多个构造方法可以使用,默认会去找是否有默认的无参构造方法,如果有就用它,没有就直接报错。(无参的构造方法本身就有一种默认的意思,兜底)

使用@Autowired注解显式指定构造方法

@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	@Autowired
	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

执行结果:

2
com.hexon.service.OrderService@35ef1869

指定另外一个构造方法:

@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	@Autowired
	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

执行结果:

1
com.hexon.service.OrderService@3427b02d

同时指定两个:

@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	@Autowired
	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	@Autowired
	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

执行结果:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService': Invalid autowire-marked constructor: public com.hexon.service.UserService(com.hexon.service.OrderService). Found constructor with 'required' Autowired annotation already: public com.hexon.service.UserService(com.hexon.service.OrderService,com.hexon.service.OrderService)

这个报错的意思是:有一个@Autowired(require=true)标记的构造方法,就不能再有其他@Autowired(无论require的值是什么)标注的构造方法,所以报错

所以下面的代码依然报错:

@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	@Autowired
	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	@Autowired(required = false)
	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

执行结果:

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService': Invalid autowire-marked constructors: [public com.hexon.service.UserService(com.hexon.service.OrderService,com.hexon.service.OrderService)]. Found constructor with 'required' Autowired annotation: public com.hexon.service.UserService(com.hexon.service.OrderService)

但是下面的代码不会报错:

@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	@Autowired(required = false)
	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	@Autowired(required = false)
	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

执行结果:

2
com.hexon.service.OrderService@35ef1869

好像是自动选择了参数最多的,后面源码再分析这种情况

要注意的是,只有通过@Autowired注解才能显式指定构造方法,其他的比如@Resource、@Primary注解是不能用在构造方法上的!

getBean时指定args参数

还有一种情况就是利用doCreateBean方法的args参数,这个我们前面的文章有提到过。

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		UserService userService = (UserService) applicationContext.getBean("userService", new OrderService());
		userService.test();
	}
}
@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

如果你直接运行,结果:

0
null

还是用的默认的无参构造方法,这是因为容器启动的时候就创建了UserService,你可以直接把UserService改成懒加载。

@Component
@Lazy
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

执行结果:

1
com.hexon.service.OrderService@30ee2816

如果改成2个参数:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		UserService userService = (UserService) applicationContext.getBean("userService", new OrderService(), new OrderService());
		userService.test();
	}
}

执行结果:

2
com.hexon.service.OrderService@31d7b7bf

如果不指定参数,就还是默认无参的。

当然这个args不完全是构造方法的参数,也可能是@Bean方法的参数,这里先了解下,后面会有单独的文章来分析@Bean。就比如可能存在下面这种情况:

@ComponentScan
public class MyConfig {

	@Bean
	public UserService userService(OrderService orderService, OrderService orderService1) {
        // 因为Spring不关注这个对象不怎么产生的,而且也不一定用@Bean方法的所有参数
		return new UserService(orderService);
	}

}

通过BeanDefinition添加构造方法参数

还有一种方式可以直接指定构造方法的参数,请思考下面的代码:

public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		// 通过参数索引赋值
		beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new OrderService());
		beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, new OrderService());
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

执行结果:

2
com.hexon.service.OrderService@188715b5

只指定一个构造方法参数:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		// 通过参数索引赋值
		beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new OrderService());
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

执行结果:

1
com.hexon.service.OrderService@59fd97a8

另外,也有不通过索引的方式指定:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		// 直接加构造方法参数
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new OrderService());
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

执行结果:

1
com.hexon.service.OrderService@795cd85e

也可以指定两个:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		// 通过参数索引赋值
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new OrderService());
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new OrderService());
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

执行结果:

2
com.hexon.service.OrderService@2f7298b

构造方法自动注入模式

还有一种自动注入的方式,前面文章我们讲过可以byType、byName,但实际上还可以根据构造方法自动注入。

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		// 设置构造器自动注入
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

执行结果:

2
com.hexon.service.OrderService@3daa422a

这种相当于是一种让Spring以更高级的方式匹配构造方法,当然前面也说过,这种机制太自动了已经不建议使用!

它的大致处理逻辑是将构造器以参数的个数降序排序,然后遍历先找第1个参数最多的构造方法,看能不能找到这个构造方法的所有参数从而执行;如果不能就找参数第2多的,再看看找不找得到参数的依赖,如果找到就直接调用,如果找不到就再用参数第3多的构造方法,以此类推....

这里我们来验证下,先改造OrderService以@Bean的方式注册:

@ComponentScan
public class MyConfig {

	@Bean
	public OrderService orderService() {
		return new OrderService();
	}

	@Bean
	public OrderService orderService1() {
		return new OrderService();
	}

}
// 无@Component注解
public class OrderService {

}
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
        // 设置构造器自动注入
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

注意:Spring6之前是先根据构造方法的参数的类型找,但是Spring6中是先根据名称找,找不到再根据参数类型。

这么说按道理上面的代码,2个参数的构造方法是用不了的,应该是会用1个参数的构造方法。因为,OrderService orderService是可以找到一个唯一的Bean的,但是OrderService orderService2根据名称也是无法筛选出唯一一个OrderService的Bean的,最终是根据类型找会筛选出两个OrderService类型的Bean。

执行结果:

1
com.hexon.service.OrderService@694abbdc

补充:这里有一个点需要注意,因为我的源码工作是通过gradle编译的,Spring源码构造时在org.springframework.build.JavaConventions类中默认是加了-parameters编译选项的(应该是插件机制,在spring-framework\buildSrc\build.gradle脚本中有指定插件),从而保证了编译后的字节码方法名是保留的,如果没有指定这个参数可能获取到的是arg0、arg1或者获取不到方法名。而像SpringBoot中是加了默认的配置的:

如果你的源码是IDEA编译的,估计就要手动给模块加下这个参数,添加方式如下:


我们修改下代码,将bean的名称改下,就可以走2个参数的构造方法了。

@ComponentScan
public class MyConfig {

	@Bean
	public OrderService orderService() {
		return new OrderService();
	}

	@Bean
	public OrderService orderService2() { // orderService1改成orderService2
		return new OrderService();
	}

}

执行结果:

2
com.hexon.service.OrderService@5f058f00

到这里我们就清楚了推断构造方法的一些处理逻辑,下面我们再仔细分析下源码的细节。

InstanceSupplier扩展点

下面我们尝试着看一下createBeanInstance方法的逻辑,源码有一个这样的判断:

if (args == null) {
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName, mbd);
    }
}

这其实是一个扩展点,我们来使用一下。

// 手动注册,无@Component
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService1) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);

		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.setInstanceSupplier(new Supplier<Object>() {
			@Override
			public Object get() {
				return User.class;
			}
		});

		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = applicationContext.getBean("userService", UserService.class);
		userService.test();
	}
}

阅读下:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#obtainFromSupplier方法就可以知道,底层的原理就是如果你有提供者,就会调用Supplier#get方法,然后包装成BeanWrapper返回。

当然上面代码是会报错的,因为User类型不能转成UserService类型。

构造方法缓存分析

跳过下面@Bean的逻辑,就会看到一个缓存的判断,具体逻辑大概是如果没有传args它会缓存构造方法和构造方法的参数值。这里我们来调试一下。

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		// beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); // 关闭自动注入
		beanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE); // 设置成多例
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		UserService userService1 = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}
public class OrderService {

}
@ComponentScan
public class MyConfig {

	@Bean
	public OrderService orderService() {
		return new OrderService();
	}

	@Bean
	public OrderService orderService2() {
		return new OrderService();
	}

}

这里我们将UserService改成了多例,并加了一个条件断点:

第2次getBean的时候就命中了缓存。后面还有一个参数值的缓存,当然按照我们当前代码,默认是无参构造所有没有缓存就直接调用默认的无参构造方法创建对象了。

其实createBeanInstance方法的最后也是调用的这个instantiateBean方法。

当然具体的参数缓存值是在autowireConstructor方法里处理的,外面的resolved和autowireNecessary只标记,我们分析下org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor方法,调用的是org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor方法。

此方法的最后就是在利用缓存的构造方法与构造方法参数值进行实例化。

当然如果没有命中缓存就会走createBeanInstance方法下面的逻辑了。

// 不知道用哪个构造方法,根据@Autowired注解来选择构造方法
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

结合@Autowired注解筛选构造方法源码分析

determineConstructorsFromBeanPostProcessors方法是用于从@Autowired注解标记的构造器筛选的,怎么会返回多个呢?这个我们上面在介绍场景时就讲过了。这里我们再详细分析下。

先调整下代码:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

这个代码就相当于直接在UserService上直接加@Component

public class OrderService {

}
@ComponentScan
public class MyConfig {

	@Bean
	public OrderService orderService() {
		return new OrderService();
	}

	@Bean
	public OrderService orderService2() {
		return new OrderService();
	}

}
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

断点调试:

当UserService中没有构造方法被@Autowired标注时:

这个很容易理解

如果给2个参数的构造方法标注:

@Autowired
public UserService(OrderService orderService, OrderService orderService2) {
    this.orderService = orderService;
    System.out.println(2);
}

返回的就是标注的这个2个参数的

但是还有其他情况,我们将@Autowired的required改成false:

@Autowired(required = false)
public UserService(OrderService orderService, OrderService orderService2) {
    this.orderService = orderService;
    System.out.println(2);
}

此时返回了两个构造方法,一个是两个参数的,一个是无参的。

再例如下面这种情况:

public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	@Autowired(required = false)
	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	@Autowired(required = false)
	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

我们给两个构造方法加了@Autowired(required = false)

结果是3个构造方法都返回了。

这个@Autowired(required = false)加在构造方法上,并不是指构造方法的参数可以没有值!推断构造方法时但凡找到了一个构造器要调用时,传入的参数一定不是空,这与@Autowired(required = false)加在属性上的含义是完全不同的。如果只在构造方法上写@Autowired(required 默认是true),代表就是明确指定用这个构造方法。而@Autowired(required = false)加在构造方法上,是代表并不一定非要用这个构造方法(类似于候选的意思:"如果依赖无法完全满足,就不要用这个构造方法")。

源码中是这样判断的:

// 如果ctors!=null,其实表示的是上一步找到了多个构造方法,接下来要继续进行推断,并进行构造方法注入
// 不管上一步根据@Autowired有没有找到构造方法,如果autowireMode为AUTOWIRE_CONSTRUCTOR,那么都会继续进行推断,并进行构造方法注入
// 如果BeanDefinition中指定了构造方法参数值,那么直接根据指定的参数值匹配构造方法,并将指定的参数值传递给构造方法
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
    mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    return autowireConstructor(beanName, mbd, ctors, args);
}

// ...跳过

// 如果上面的都不满足就会用默认的无参的

这意味着,当返回3个(多个)时会用更高级的方式推断(就是我们前面讲的AUTOWIRE_CONSTRUCTOR的方式)。所以最终的执行结果就是调用参数最多的构造方法(当然前提是构造方法的参数都能成功注入):

2
com.hexon.service.OrderService@3e11f9e9

另外,如果是一个构造方法是@Autowired(required = false),一个构造方法是@Autowired是会报错的:

public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	@Autowired
	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	@Autowired(required = false)
	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

执行结果:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService': Invalid autowire-marked constructors: [public com.hexon.service.UserService(com.hexon.service.OrderService,com.hexon.service.OrderService)]. Found constructor with 'required' Autowired annotation: public com.hexon.service.UserService(com.hexon.service.OrderService)

这个情况最开始我们就讲过

我们再详细分析下内部是怎么找的

调用链路
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors
org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
    throws BeanCreationException {

    // 处理@Lookup注解
    checkLookupMethods(beanClass, beanName);

    // Quick check on the concurrent map first, with minimal locking.
    Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
    if (candidateConstructors == null) {
        // Fully synchronized resolution now...
        synchronized (this.candidateConstructorsCache) {
            candidateConstructors = this.candidateConstructorsCache.get(beanClass);
            if (candidateConstructors == null) {
                Constructor<?>[] rawCandidates;
                try {
                    rawCandidates = beanClass.getDeclaredConstructors();
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(beanName,
                                                    "Resolution of declared constructors on bean Class [" + beanClass.getName() +
                                                    "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
                }
                List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                Constructor<?> requiredConstructor = null;
                Constructor<?> defaultConstructor = null;
                Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                int nonSyntheticConstructors = 0;

                // 遍历所有构造方法
                for (Constructor<?> candidate : rawCandidates) {
                    if (!candidate.isSynthetic()) {
                        nonSyntheticConstructors++;
                    }
                    else if (primaryConstructor != null) {
                        continue;
                    }
                    // 判断当前构造方法上是否有@Autowired注解
                    MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
                    if (ann == null) {
                        // 如果beanClass是代理类,比如cglib,那么就找他的父类,也就是被代理类
                        Class<?> userClass = ClassUtils.getUserClass(beanClass);
                        if (userClass != beanClass) {
                            try {
                                Constructor<?> superCtor =
                                    userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                ann = findAutowiredAnnotation(superCtor);
                            }
                            catch (NoSuchMethodException ex) {
                                // Simply proceed, no equivalent superclass constructor found...
                            }
                        }
                    }
                    // 如果当前构造方法上有@Autowired注解
                    if (ann != null) {

                        // 一个类中只能有一个@Autowired注解的构造方法,有多个会报错
                        // 但可以有多个加了@Autowired(require = false)的构造方法
                        if (requiredConstructor != null) {
                            throw new BeanCreationException(beanName,
                                                            "Invalid autowire-marked constructor: " + candidate +
                                                            ". Found constructor with 'required' Autowired annotation already: " +
                                                            requiredConstructor);
                        }
                        boolean required = determineRequiredStatus(ann);
                        if (required) {
                            if (!candidates.isEmpty()) {
                                throw new BeanCreationException(beanName,
                                                                "Invalid autowire-marked constructors: " + candidates +
                                                                ". Found constructor with 'required' Autowired annotation: " +
                                                                candidate);
                            }
                            requiredConstructor = candidate;
                        }
                        candidates.add(candidate);
                    }
                    // 如果当前构造方法上没有@Autowired注解,并且参数个数为0,则单独记录到时defaultConstructor
                    else if (candidate.getParameterCount() == 0) {
                        defaultConstructor = candidate;
                    }
                }
                // 遍历结束

                // candidates中的记录是那些加了@Autowired的构造方法(如果是多个那么require肯定是false)
                if (!candidates.isEmpty()) {
                    // Add default constructor to list of optional constructors, as fallback.
                    if (requiredConstructor == null) {
                        // 没有require为true的,就把无参数的构造方法也加进来
                        if (defaultConstructor != null) {
                            candidates.add(defaultConstructor);
                        }
                        else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                            logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
                                        "': single autowire-marked constructor flagged as optional - " +
                                        "this constructor is effectively required since there is no " +
                                        "default constructor to fall back to: " + candidates.get(0));
                        }
                    }
                    candidateConstructors = candidates.toArray(EMPTY_CONSTRUCTOR_ARRAY);
                }
                // 类中没有加了@Autowired注解的构造方法,rawCandidates表示类中的所有构造方法,如果只有一个构造方法,那就返回这一个
                else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                    candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
                }
                // Kotlin相关的,不管
                else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                         defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
                }
                // Kotlin相关的,不管
                else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor};
                }
                else {
                    candidateConstructors = EMPTY_CONSTRUCTOR_ARRAY;
                }
                this.candidateConstructorsCache.put(beanClass, candidateConstructors);
            }
        }
    }

    // 最终返回的是那些加了@Autowired注解的构造方法(只有一个@Autowired注解的,或者多个都是@Autowired(require = false)注解的)
    // 如果类中的构造方法都没有加@Autowired注解,如果有多个构造方法,那么就会返回null,如果只有一个,那么就会返回这唯一的一个
    return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

这个源码很重要,它包含我们前面分析常见应用场景的大部分逻辑处理。

此方法并不负责依赖注入,它只是告诉下一步要用哪些构造方法,如果返回多个,后面的源码还有筛选处理逻辑的。

总结:

// 不知道用哪个构造方法,结合@Autowired注解来选择构造方法
// Candidate constructors for autowiring?
// 1. 如果只有一个@Autowired注解的构造方法,就返回这个
// 2. 如果有多个加了@Autowired(require = false)注解的构造方法,就返回这几个构造方法+无参的构造方法
// 3. 如果类中的构造方法都没有加@Autowired注解,如果有多个构造方法,那么就会返回null,如果只有一个,那么就会返回这唯一的一个
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

如果ctors是空并且未开启其他3种情况(见源码的if判断)就会向下走,下面有一段是获取首选构造方法的代码:

// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
    return autowireConstructor(beanName, mbd, ctors, null);
}

下面来演示下这种情况:

public class Main {
	public static void main(String[] args) throws NoSuchMethodException {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		// beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); // 关闭自动注入
		Constructor<?> preferredConstructor = UserService.class.getConstructor(OrderService.class);
        // 指定首选构造方法
		beanDefinition.setAttribute(AbstractBeanDefinition.PREFERRED_CONSTRUCTORS_ATTRIBUTE, preferredConstructor);
		applicationContext.registerBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

只需要满足3种情况就可以:

  • 当Bean没有使用 @Autowired 注解

  • 当没有设置自动装配模式为构造方法

  • 当没有通过其他方式指定构造方法

输出结果:

1
com.hexon.service.OrderService@2ea41516

当然,如果不满足if里面的判断,也没有指定首选构造方法,最终会调用

// No special handling: simply use no-arg constructor.
// 如果到了这一步,那就直接调用无参构造方法来实例化得到的对象了
return instantiateBean(beanName, mbd);

没有无参的就会报错

但是如果ctors不是空或者其他3种情况(见源码的if判断)就会走org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor方法,此方法大概的逻辑就是会优先找参数最多,且参数值的依赖都能找到的构造方法进行依赖注入。前面分析缓存的时候,稍微看过这个方法,下面我们再来详细分析autowireConstructor方法。

构造方法注入底层源码解析

内容回顾

首先我们还是回顾下外层的判断逻辑:

if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
    mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    return autowireConstructor(beanName, mbd, ctors, args);
}

if中的4个条件我们之前都已经演练过了,这里简单回顾一下。思考下面的代码:

public class OrderService {​}
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	@Autowired
	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}
@ComponentScan
public class MyConfig {

	@Bean
	public OrderService orderService() {
		return new OrderService();
	}

	@Bean
	public OrderService orderService2() {
		return new OrderService();
	}

}
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

上面的代码使用@Autowired注解显式指定了一个,所以断点的情况就是两个参数的,而且mbd的autowireMode也是构造方法:

断点条件:"userService".equals(beanName)

但是如果没有@Autowired修饰:

public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

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

}

那么ctors返回的就是null,这个我们前面分析过,但是自动注入模式的判断是满足的。

自动推断构造方法底层源码解析

现在进入autowireConstructor调试:

进入后有一个判断:

// explicitArgs表示getBean()指定了参数值
if (explicitArgs != null) {
    argsToUse = explicitArgs;
}

目前我们没有指定,所以会往下走,另外因为是第一次执行所有也没有缓存。

这个地方目前构造方法以及构造方法的参数值都是不知道的,但有一种情况就是getBean时指定了参数,那么就可能出现constructorToUse为null,argsToUse不为null的情况。这里只是args的判断,关于BeanDefinition中添加构造方法参数的逻辑这里还没有看到。

再往下的一个判断:

这个其实就是在判断外面(上一步,我们过分析的)传进来的chosenCtors有没有值,如果有就用传进来的继续判断,如果没有就获取所有的构造方法。接着又有一个判断:

// 如果可选构造方法只有一个
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
    Constructor<?> uniqueCandidate = candidates[0];
    // 并且这是一个无参构造方法,那么就只能用这一个了
    if (uniqueCandidate.getParameterCount() == 0) {
        synchronized (mbd.constructorArgumentLock) {
            mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
            mbd.constructorArgumentsResolved = true;
            mbd.resolvedConstructorArguments = EMPTY_ARGS;
        }
        // 直接实例化并return
        bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
        return bw;
    }
}

这个相当于一个额外的判断,就是只有一个无参构造方法,那么就只能用这一个了。

再往下面又有一段处理:

// Need to resolve the constructor.
boolean autowiring = (chosenCtors != null ||
                      mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;

// minNrOfArgs表示需要的构造方法的最小参数个数
// 会根据getBean()或者BeanDefinition中指定的构造方法参数值来决定最小参数个数
// 接下来遍历过程中,直接过滤掉参数个数小于minNrOfArgs的构造方法
int minNrOfArgs;
if (explicitArgs != null) {
    minNrOfArgs = explicitArgs.length;
}
else {
    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
    resolvedValues = new ConstructorArgumentValues();

    // RuntimeBeanReference 是什么?
    // 当 Spring 解析配置时,遇到 <constructor-arg ref="beanB"> 这样的引用,它会创建一个 RuntimeBeanReference 对象作为占位符
    // 这个对象表示"这里需要引用另一个名为 'beanB' 的 bean"
    // 这里会去解析RuntimeBeanReference,也就是把配置中类似 ref="beanB" 的引用,转换成实际的 Spring Bean 对象。
    minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}

这里有两种情况,一种是args指定,一种是通过解析BeanDefinition中指定的构造方法参数个数。

假设我们代码中通过getBean明确指定了参数:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = (UserService) applicationContext.getBean("userService", new OrderService(), new OrderService()); // 明确指定参数个数
		userService.test();
	}
}

此时minNrOfArgs会为2:

通过BeanDefinition指定构造方法的参数:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, new OrderService()); // 通过索引指定构造方法参数
		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

这里要注意的是索引是1,代表至少有两个构造方法参数,那么minNrOfArgs也会为2:

当然如果两个都没有指定minNrOfArgs默认就是0。

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

总之,这个minNrOfArgs变量就是要计算出满足条件的构造方法至少有几个参数。

再接下来有一个排序的操作:

// 对构造方法进行排序,public的排在非public的前面,参数个数多的排在参数个数少的前面
AutowireUtils.sortConstructors(candidates);

再后面就是遍历每一个构造方法了:

// 遍历每个构造方法
for (Constructor<?> candidate : candidates) {
    int parameterCount = candidate.getParameterCount();

    if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
        // Already found greedy constructor that can be satisfied ->
        // do not look any further, there are only less greedy constructors left.
        break;
    }

    // 过滤掉参数个数小于minNrOfArgs的构造方法
    if (parameterCount < minNrOfArgs) {
        continue;
    }

    ArgumentsHolder argsHolder;
    // 取出参数类型
    Class<?>[] paramTypes = candidate.getParameterTypes();

    // 如果getBean()方法指定了参数值,那么resolvedValues会为null
    if (resolvedValues != null) {
        try {
            String[] paramNames = null;
            if (resolvedValues.containsNamedArgument()) {
                paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
                if (paramNames == null) {
                    ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                    if (pnd != null) {
                        paramNames = pnd.getParameterNames(candidate);
                    }
                }
            }
            // paramTypes表示当前构造方法各个参数的参数类型
            // paramNames表示当前构造方法各个参数的参数名,通过@ConstructProperties来指定
            // 这个方法的返回值就是当前构造方法所匹配到的参数值
            argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                                             getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
        }
        catch (UnsatisfiedDependencyException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
            }
            // Swallow and try next constructor.
            if (causes == null) {
                causes = new ArrayDeque<>(1);
            }
            causes.add(ex);
            continue;
        }
    }
    else {
        // 其他情况resolvedValues != null

        // Explicit arguments given -> arguments length must match exactly.
        // 当前构造方法的参数不等于getBean指定的参数个数,那么当前构造方法不合适
        if (parameterCount != explicitArgs.length) {
            continue;
        }
        // 如果参数个数相等,那么当前构造方法就合适,并且构造方法的参数值就是getBean指定的。
        argsHolder = new ArgumentsHolder(explicitArgs);
    }

    // 根据找到的构造方法参数值,和当前构造方法的参数类型,计算typeDiffWeight
    // 最终取typeDiffWeight最小的那个构造方法
    int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                          argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
    // Choose this constructor if it represents the closest match.
    if (typeDiffWeight < minTypeDiffWeight) {
        constructorToUse = candidate;
        argsHolderToUse = argsHolder;
        argsToUse = argsHolder.arguments;
        minTypeDiffWeight = typeDiffWeight;
        ambiguousConstructors = null;
    }
    else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
        if (ambiguousConstructors == null) {
            ambiguousConstructors = new LinkedHashSet<>();
            ambiguousConstructors.add(constructorToUse);
        }
        ambiguousConstructors.add(candidate);
    }
}
// 遍历结束

下面我们来调试一下,我们使用getBean方法指定一个参数:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = (UserService) applicationContext.getBean("userService", new OrderService());
		userService.test();
	}
}

设置断点:

先遍历的是2个参数的构造方法,理论上,好像也可以使用它,但由于else分支是有一个判断的:

所以,getBean传入参数的情况,如果构造方法的参数个数不匹配会直接跳过。下面的逻辑走完,最终就是用一个参数的那个:

输出结果:

1
com.hexon.service.OrderService@6392827e

下面再看另外的一种情况,使用BeanDefinition通过非索引的方式指定构造方法参数:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new OrderService());
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

一样的加断点进行调试,我们看下minNrOfArgs的值:

最终也是1,这个可以理解,我没有用下标指定参数,而是只传递了1个参数,所以至少就是1个参数。但是它能不能用两个参数的构造方法呢?这个地方会和getBean传递参数源码走的逻辑还是有区别的。

此时resolvedValues变量是有值的,在上面的else分支中有赋值:

所以说resolvedValues这个变量其实就是在区分有没有使用getBean指定参数。我们是用的BeanDefinition指定的参数,所以会进入if判断:

进来后又有一个判断,这个先跳过,反正不会进入:

而这个createArgumentArray方法就是重点了,它会去根据构造器的参数类型和名称找Bean,并最终返回值当前构造方法所匹配到的参数值。

找不到会进入catch,但是会继续循环。createArgumentArray方法的逻辑可以自己调试下,针对我们现在的测试代码,大概的逻辑是:

首先会找到paramIndex为0的值,这个就是我们通过BeanDefinition指定的,但是paramIndex为1的也会去通过依赖查找找到,因为我们定义了orderService2这个Bean。

最终会走2个参数的构造方法,输出如下:

> Task :spring-demo:Main.main()
2
com.hexon.service.OrderService@6aba2b86

下面还有一个typeDiffWeight的判断,我们来分析下。

严格模式和宽松模型底层源码解析

根据源码可以知道,如果找到了构造方法的所有参数值,会判断是不是宽松模式,从而决定用哪种方式计算一个权重。

// 根据找到的构造方法参数值,和当前构造方法的参数类型,计算typeDiffWeight
				// 最终取typeDiffWeight最小的那个构造方法
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                      argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));

然后是在循环内,每次会判断迭代,从而到循环结束的时候就能选择唯一的一个符合条件的构造方法。

看到这里,不妨先想一想为什么要计算权重呢?一个最容易想到的情况就是构造器方法参数个数一样,那就是构造方法重载呗!

下面我们开始分析,因为构造方法要参数一样才能进来,不然会break掉。

所以我们改下示例代码:

public interface OrderInterface {
}
public class UserService {

	private OrderService orderService;

	public UserService() {
		System.out.println(0);
	}

	public UserService(OrderService orderService) {
		this.orderService = orderService;
		System.out.println(1);
	}

	public UserService(OrderService orderService, OrderService orderService2) {
		this.orderService = orderService;
		System.out.println(2);
	}

	public UserService(OrderService orderService, OrderInterface orderService2) {
		this.orderService = orderService;
		System.out.println(3);
	}

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

}
@ComponentScan
public class MyConfig {

	@Bean
	public OrderService orderService() {
		return new OrderService();
	}

	@Bean
	public OrderService orderService2() {
		return new OrderService();
	}

}
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new OrderService());
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

下面我们来调试一下,断点:

要注意的是,默认是宽松模式,我们来看下两个构造方法最后的分数:

首先进来的是编号3(输出3)的那个构造方法,它的权重值是-1023。

再进来的是编号2(输出2)的那个构造方法,它的权重值是-1024。

最终会用分数小的,打印结果的值如下:

2
com.hexon.service.OrderService@201a4587

而上面的代码,我们如果采用严格模式:

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new OrderService());
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
        // 严格模式
		beanDefinition.setLenientConstructorResolution(false);
		applicationContext.registerBeanDefinition("userService", beanDefinition);

		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
	}
}

执行的结果会报错:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService': Ambiguous constructor matches found on bean class [com.hexon.service.UserService] (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): [public com.hexon.service.UserService(com.hexon.service.OrderService,com.hexon.service.OrderInterface), public com.hexon.service.UserService(com.hexon.service.OrderService,com.hexon.service.OrderService)]

这个是因为非宽松模式下,两个构造方法的分数一样的,如何理解呢?

宽松模式:就是条件多样化一点,比如公司卡学历,但是你技术可以还是可能要你。

严格模式:条件单一一点,比如公司卡学历,非本科就不要你来面试。


严格模式

严格模式计算权重的方式比较简单粗暴:

public int getAssignabilityWeight(Class<?>[] paramTypes) {
    for (int i = 0; i < paramTypes.length; i++) {
        // 如果类型不匹配就返回一个很大的值
        if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) {
            return Integer.MAX_VALUE;
        }
    }
    for (int i = 0; i < paramTypes.length; i++) {
        if (!ClassUtils.isAssignableValue(paramTypes[i], this.rawArguments[i])) {
            return Integer.MAX_VALUE - 512;
        }
    }
    // 如果类型匹配就返回这个值
    return Integer.MAX_VALUE - 1024;
}

这个地方可以调试下代码,就可以看到两个构造方法返回的值都是:Integer.MAX_VALUE - 1024

宽松模式

这个可以直接看MethodInvoker.getTypeDifferenceWeight方法的源码就能明白,这里我们演练一下。

public class A extends B implements D {
}
public class B extends C {
}
public class C {
}
public interface D {
}
public class Main {
	public static void main(String[] args) {
		Object[] objects = new Object[]{new A()};
		// 0
		System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class<?>[]{A.class}, objects));
		// 2
		System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class<?>[]{B.class}, objects));
		// 4
		System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class<?>[]{C.class}, objects));
		// 1
		System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class<?>[]{D.class}, objects));
		// 2147483647
		System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class<?>[]{UserService.class}, objects));
	}
}