V哥官网:http://www.vgxit.com
本博客对应视频教程:http://www.vgxit.com/course/23
构造方法注入和set注入
1,概述
我们上节课讲了一下IOC入门,然后我们注入了一个对象到Spring容器,并且通过Spring容器获取到了这个对象。但是,我们思考一下,我们说道了注入就是我们创建一个对象然后把这个对象提交到Spring容器。那么我们思考一下他是如何创建这个对象的呢?
2,无参构造方法注入
所谓无参构造方法注入就是Spring会自动调用我们无参构造方法来创建一个对象,然后再把这个对象提交到Spring容器。像我们上节课讲的入门案例。我们创建Person对象不需要提交任何的参数。
3,有参构造方法注入
对于有一些对象,他有一些属性,这些属性的初始化是通过构造方法传递进去的。这个时候,我们创建对象的时候必须要指定对应的参数。Spring也给我们提供了通过构造器传入参数注入对象的方法。
1,改造一下Person:
package com.vgxit.spring.ktdm.vgioc.beans;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class Person {
private Integer id;
private String name;
public void sayHello(String name) {
System.out.println(this.id + ":" + this.name + " say hello to " + name);
}
}
2,修改注入配置:
<!--
bean标签用来定义一个需要Spring创建并且注入到IOC容器的对象
id表示这个对象的名字
class表示类型
-->
<bean id="person" class="com.vgxit.spring.ktdm.vgioc.beans.Person">
<!--
<constructor-arg/>标签就表示对应的构造方法的参数
index表示参数的位置,从0开始的
value表示参数的值
-->
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="V哥"/>
</bean>
3,测试:
package com.vgxit.spring.ktdm.vgioc.test;
import com.vgxit.spring.ktdm.vgioc.beans.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Ioc001Test {
public static void main(String[] args) {
//1,首先通过配置文件获取到Spring的上下文
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-ioc-cfg.xml");
//2,获取对应的对象,通知Spring的Ioc容器,我需要一个名字叫做Person的bean
Person person = (Person) ctx.getBean("person");
//调用方法
person.sayHello("李一桐");
}
}
4,有参构造方法注入缺陷
我们上面讲了有参构造方法实现注入。但是我们在实际的开发中,基本上没人使用有参构造方法来实现注入。因为有参构造方法的注入是有非常大的缺陷的。下面我们演示一下这个缺陷。
1,改造Person:
package com.vgxit.spring.ktdm.vgioc.beans;
public class Person {
private Integer id;
private String name;
private String nickName;
public Person(String name, String nickName) {
this.name = name;
this.nickName = nickName;
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
public void sayHello(String name) {
System.out.println(this.id + ":" + this.name + "[" + this.nickName + "]" + " say hello to " + name);
}
}
这个时候,我们传入如下参数:
<bean id="person" class="com.vgxit.spring.ktdm.vgioc.beans.Person">
<!--
<constructor-arg/>标签就表示对应的构造方法的参数
index表示参数的位置,从0开始的
value表示参数的值
-->
<constructor-arg index="0" value="V哥"/>
<constructor-arg index="1" value="V哥学IT"/>
</bean>
这个时候我们可以发现Spring调用了Person的Person(String name, String nickName)方法。但是,如果我们改成下面的参数传入:
<bean id="person" class="com.vgxit.spring.ktdm.vgioc.beans.Person">
<!--
<constructor-arg/>标签就表示对应的构造方法的参数
index表示参数的位置,从0开始的
value表示参数的值
-->
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="V哥学IT"/>
</bean>
这个时候,还是调用的Person(String name, String nickName)。但是我们实际上是想调用Person(Integer id, String name)。但是我们发现Spring永远没有办法帮我们调用到。因为Spring调用有参构造方法的逻辑按照构造方法定义的顺序,从上往下找到第一个满足参数个数匹配的方法来调用。
5,基于Setter的注入
setter注入是Spring中最流行的注入方式,它的原理是先调用无参构造方法来创建对象,然后调用对应的set方法来为属性赋值。用setter的方式可以解决有参构造方法注入的问题。并且可以提高可读性。
1,改造Person:
package com.vgxit.spring.ktdm.vgioc.beans;
import lombok.Setter;
@Setter
public class Person {
private Integer id;
private String name;
private String nickName;
public void sayHello(String name) {
System.out.println(this.id + ":" + this.name + "[" + this.nickName + "]" + " say hello to " + name);
}
}
2,通过property标签来注入对应的属性:
<bean id="person" class="com.vgxit.spring.ktdm.vgioc.beans.Person">
<property name="id" value="1"/>
<property name="name" value="V哥"/>
<property name="nickName" value="V哥学IT"/>
</bean>