在spring bean的生命周期中,有一个步骤是实例化对象,在这里需要推断构造方法,本篇文章将讲解Spring是如何推断构造方法的。
1、推断构造方法结论
- 默认用无参构造方法、如果只有一个构造方法,那么就用那一个。
比如下面这个例子,User 类里有三个构造方法,一个无参构造方法,两个有参构造方法,那么spring默认用无参构造方法:
@Component
public class User {
@Autowired
private 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");
}
}
@Component
public 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) {
// 注解方法注册bean
ApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);
User u = context.getBean(User.class);
u.say();
}
}
打印结果:
construct 1
hi 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) {
// 注解方法注册bean
ApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);
User u = context.getBean(User.class,Dog.class);
u.say();
}
}
打印结果:
construct 1
hi i am tom
- 如果程序员指定了某个构造方法(用@Autowired指定),那么,就用这个构造方法。
比如,还是上面的例子,我们在User类里的,有2个参数的构造方法上打上@Autowired注解,表示想用这个构造方法,那么spring就会用这个构造方法:
@Component
public class User {
@Autowired
private Dog dog;
public User() {
System.out.println("construct 1");
}
public User(Dog dog) {
this.dog = dog;
System.out.println("construct 2");
}
@Autowired
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) {
// 注解方法注册bean
ApplicationContext context = new AnnotationConfigApplicationContext(MainStart.class);
User u = context.getBean(User.class);
u.say();
}
}
打印结果:
construct 2
hi 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/beans
http://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 {
@Autowired
private 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) {
// // 原始方法注册bean
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
User user = (User)context.getBean("user");
user.say();
}
}
打印结果:
construct 2
hi i am tom