在spring bean的生命周期中,有一个步骤是实例化对象,在这里需要推断构造方法,本篇文章将讲解Spring是如何推断构造方法的。
1、推断构造方法结论
- 默认用无参构造方法、如果只有一个构造方法,那么就用那一个。
比如下面这个例子,User 类里有三个构造方法,一个无参构造方法,两个有参构造方法,那么spring默认用无参构造方法:
@Componentpublic class User {@Autowiredprivate Dog dog;public User() {System.out.println("construct 1");}public User(Dog dog) {this.dog = dog;System.out.println("construct 2");}public User(Dog dog, Dog dog2) {this.dog = dog;System.out.println("construct 2");}void say() {System.out.println("hi i am tom");}}@Componentpublic class Dog {void say() {System.out.println("hi i am a dog name is wangwang");}}
@Configuration@ComponentScan("com.ioc.tuing.impl")public class MainStart {public static void main(String[] args) {// 注解方法注册beanApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);User u = context.getBean(User.class);u.say();}}
打印结果:
construct 1hi i am tom
若上面的代码,注释掉无参构造方法,和一个参数的构造方法,那么打印结果就会显示,spring用的就是这个仅剩的2个参数的构造方法。
- 如果程序员指定构造方法入参值(通过getBean()或BeanDefination.getConstructorArgumentValues()指定),那么就用所匹配的构造方法。
例如下面单位例子,getBean()方法传入了一个参数,即使user类里面有三个构造方法,spring依然会根据参数匹配,找到哪个只有一个参数的构造方法:
@Configuration@ComponentScan("com.ioc.tuing.impl")public class MainStart {public static void main(String[] args) {// 注解方法注册beanApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);User u = context.getBean(User.class,Dog.class);u.say();}}
打印结果:
construct 1hi i am tom
- 如果程序员指定了某个构造方法(用@Autowired指定),那么,就用这个构造方法。
比如,还是上面的例子,我们在User类里的,有2个参数的构造方法上打上@Autowired注解,表示想用这个构造方法,那么spring就会用这个构造方法:
@Componentpublic class User {@Autowiredprivate Dog dog;public User() {System.out.println("construct 1");}public User(Dog dog) {this.dog = dog;System.out.println("construct 2");}@Autowiredpublic User(Dog dog, Dog dog2) {this.dog = dog;System.out.println("construct 2");}void say() {System.out.println("hi i am tom");}}
@Configuration@ComponentScan("com.ioc.tuing.impl")public class MainStart {public static void main(String[] args) {// 注解方法注册beanApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);User u = context.getBean(User.class);u.say();}}
打印结果:
construct 2hi i am tom
- 如果程序员没有指定用哪个构造方法,则看开发者有没有让Spring自动去选择构造方法。
对于这一点,只能用ClassPathXmlApplicationContext演示去指定让Spring自己去选择构造方法(autowire=”constructor”),因为AnnotationConfigApplicationContext没办法指定某个bean让它自己选择构造方法。
若指定了让spring去选择构造方法,那么最终会优先用参数多的构造方法。
若没有指定,则Spring还是会选择默认的无参构造方法。
下面的例子,指定了让Spring自己去选择构造方法,可以看到,spring选择了带有2个参数的构造方法。
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.ioc.tuing.impl.User" autowire="constructor"></bean><bean id="dog" class="com.ioc.tuing.impl.Dog"></bean></beans>
public class User {@Autowiredprivate Dog dog;public User() {System.out.println("construct 1");}public User(Dog dog) {this.dog = dog;System.out.println("construct 2");}public User(Dog dog, Dog dog2) {this.dog = dog;System.out.println("construct 2");}void say() {System.out.println("hi i am tom");}}
@Configuration@ComponentScan("com.ioc.tuing.impl")public class MainStart {public static void main(String[] args) {// // 原始方法注册beanClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");User user = (User)context.getBean("user");user.say();}}
打印结果:
construct 2hi i am tom
