在spring bean的生命周期中,有一个步骤是实例化对象,在这里需要推断构造方法,本篇文章将讲解Spring是如何推断构造方法的。

1、推断构造方法结论

  • 默认用无参构造方法、如果只有一个构造方法,那么就用那一个。

比如下面这个例子,User 类里有三个构造方法,一个无参构造方法,两个有参构造方法,那么spring默认用无参构造方法:

  1. @Component
  2. public class User {
  3. @Autowired
  4. private Dog dog;
  5. public User() {
  6. System.out.println("construct 1");
  7. }
  8. public User(Dog dog) {
  9. this.dog = dog;
  10. System.out.println("construct 2");
  11. }
  12. public User(Dog dog, Dog dog2) {
  13. this.dog = dog;
  14. System.out.println("construct 2");
  15. }
  16. void say() {
  17. System.out.println("hi i am tom");
  18. }
  19. }
  20. @Component
  21. public class Dog {
  22. void say() {
  23. System.out.println("hi i am a dog name is wangwang");
  24. }
  25. }
  1. @Configuration
  2. @ComponentScan("com.ioc.tuing.impl")
  3. public class MainStart {
  4. public static void main(String[] args) {
  5. // 注解方法注册bean
  6. ApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);
  7. User u = context.getBean(User.class);
  8. u.say();
  9. }
  10. }

打印结果:

  1. construct 1
  2. hi i am tom

若上面的代码,注释掉无参构造方法,和一个参数的构造方法,那么打印结果就会显示,spring用的就是这个仅剩的2个参数的构造方法。

  • 如果程序员指定构造方法入参值(通过getBean()或BeanDefination.getConstructorArgumentValues()指定),那么就用所匹配的构造方法。

例如下面单位例子,getBean()方法传入了一个参数,即使user类里面有三个构造方法,spring依然会根据参数匹配,找到哪个只有一个参数的构造方法:

  1. @Configuration
  2. @ComponentScan("com.ioc.tuing.impl")
  3. public class MainStart {
  4. public static void main(String[] args) {
  5. // 注解方法注册bean
  6. ApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);
  7. User u = context.getBean(User.class,Dog.class);
  8. u.say();
  9. }
  10. }

打印结果:

  1. construct 1
  2. hi i am tom
  • 如果程序员指定了某个构造方法(用@Autowired指定),那么,就用这个构造方法。

比如,还是上面的例子,我们在User类里的,有2个参数的构造方法上打上@Autowired注解,表示想用这个构造方法,那么spring就会用这个构造方法:

  1. @Component
  2. public class User {
  3. @Autowired
  4. private Dog dog;
  5. public User() {
  6. System.out.println("construct 1");
  7. }
  8. public User(Dog dog) {
  9. this.dog = dog;
  10. System.out.println("construct 2");
  11. }
  12. @Autowired
  13. public User(Dog dog, Dog dog2) {
  14. this.dog = dog;
  15. System.out.println("construct 2");
  16. }
  17. void say() {
  18. System.out.println("hi i am tom");
  19. }
  20. }
  1. @Configuration
  2. @ComponentScan("com.ioc.tuing.impl")
  3. public class MainStart {
  4. public static void main(String[] args) {
  5. // 注解方法注册bean
  6. ApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);
  7. User u = context.getBean(User.class);
  8. u.say();
  9. }
  10. }

打印结果:

  1. construct 2
  2. hi i am tom
  • 如果程序员没有指定用哪个构造方法,则看开发者有没有让Spring自动去选择构造方法。

对于这一点,只能用ClassPathXmlApplicationContext演示去指定让Spring自己去选择构造方法(autowire=”constructor”),因为AnnotationConfigApplicationContext没办法指定某个bean让它自己选择构造方法。
若指定了让spring去选择构造方法,那么最终会优先用参数多的构造方法。
若没有指定,则Spring还是会选择默认的无参构造方法。
下面的例子,指定了让Spring自己去选择构造方法,可以看到,spring选择了带有2个参数的构造方法。

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:p="http://www.springframework.org/schema/p"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="user" class="com.ioc.tuing.impl.User" autowire="constructor"></bean>
  7. <bean id="dog" class="com.ioc.tuing.impl.Dog"></bean>
  8. </beans>
  1. public class User {
  2. @Autowired
  3. private Dog dog;
  4. public User() {
  5. System.out.println("construct 1");
  6. }
  7. public User(Dog dog) {
  8. this.dog = dog;
  9. System.out.println("construct 2");
  10. }
  11. public User(Dog dog, Dog dog2) {
  12. this.dog = dog;
  13. System.out.println("construct 2");
  14. }
  15. void say() {
  16. System.out.println("hi i am tom");
  17. }
  18. }
  1. @Configuration
  2. @ComponentScan("com.ioc.tuing.impl")
  3. public class MainStart {
  4. public static void main(String[] args) {
  5. // // 原始方法注册bean
  6. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  7. User user = (User)context.getBean("user");
  8. user.say();
  9. }
  10. }

打印结果:

  1. construct 2
  2. hi i am tom