Spring使用set注入为属性赋值
- set注入
-
- 简单类型的注入
- 引用类型的注入
- 构造注入
- 自动注入
-
- 按照名称进行注入
- 按照类型注入
- 按照构造自动注入
注入就是赋值的意思
Spring规定:Java中的基本数据类型和字符串都是简单数据类型
set注入的本质是调用set方法来赋值,因此在使用此方法注入时set方法必不可少
set注入
简单类型的注入
先创建一个简单的Hello类,定义一个属性及其的set方法
public class Hello {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
在xml文件里使用set注入为Hello类里面的属性赋值
切记别名不可重复
<!--id是对象的别名,class是绝对路径-->
<bean id="hello" class="spring.service.ba01.Hello">
<!--name是属性名,value属性值-->
<property name="msg" value="Hello world"/>
</bean>
在HelloWorld类里面实例化出Hello类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloWorld {
public static void main(String[] args) {
//存储xml文件的路径
String config = "ba01/ba01.xml";
//生成ac,以便于实例化对象
ApplicationContext ac =new ClassPathXmlApplicationContext(config);
//实例化对象,hello就是xml文件中给Hello起的别名
Hello hello = (Hello)ac.getBean("hello");
System.out.println(hello.getMsg());
}
}
结果如图所示,Hello已被实例化出来了
集合属性注入
//在Hello类加入属性
private List<String>list;
private Set<String> set;
private Map<String, String> map;
xml文件配置
<property name="list">
<list>
<value>a</value>
<value>b</value>
<value>c</value>
</list>
</property>
<property name="map">
<map>
<entry key="a" value="aaa"></entry>
<entry key="b" value="bbb"></entry>
</map>
</property>
<property name="set">
<set>
<value>1</value>
<value>2</value>
<value>1</value>
</set>
</property>
结果
引用类型的注入
创建school类
public class school {
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
创建student类
public class student {
private school school;
private String name;
@Override
public String toString() {
return "我叫:"+getName()+",我在位处于:"+school.getAddress()+"的名字叫:"+school.getName()+"上学";
}
public spring.service.ba01.school getSchool() {
return school;
}
public void setSchool(spring.service.ba01.school school) {
this.school = school;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
编写xml文件
<bean id="school" class="spring.service.ba01.school">
<property name="name" value="清华"/>
<property name="address" value="北京"/>
</bean>
<bean id="student" class="spring.service.ba01.student">
<property name="name" value="张三"/>
<property name="school" ref="school"/>
</bean>
编写测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
String config = "ba01/ba01.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
student student = (student)ac.getBean("student");
System.out.println(student);
}
}
测试结果如图赋值成功
构造注入即使用构造方法注入,而不使用set方法,也就是说不一定必须要写set方法,但是有参构造必须存在
创建Student类和School类
public class School {
private String name;
private String address;
public School(String name, String address) {
this.name = name;
this.address = address;
}
@Override
public String toString() {
return "School{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
public class Student {
private School school;
private String name;
private int age;
public Student(School school, String name, int age) {
this.school = school;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"school=" + school +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
在xml文件里使用构造注入为属性赋值
<bean id="SC" class="com.demo.test1.School">
<constructor-arg name="address" value="北京"></constructor-arg>
<constructor-arg name="name" value="北大"></constructor-arg>
</bean>
<bean id="stu" class="com.demo.test1.Student">
<constructor-arg index="0" ref="SC"></constructor-arg>
<constructor-arg index="1" value="张三"></constructor-arg>
<constructor-arg index="2" value="20"></constructor-arg>
</bean>
上述代码可以看出,构造注入的俩种写法,一种是name使用属性名来确定属性,另一种使用index,他是从0开始计算的
测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
String config = "classpath:spring/ApplicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
Student student = (Student)ac.getBean("stu");
System.out.println(student);
}
}
结果
自动注入自动注入是采用约定大约配置的方式来实现的,程序和spring容器之间约定好,遵守某一种都认同的规则,来实现自动注入。
xml中可以在bean元素中通过autowire属性来设置自动注入的方式,autowire分为三种按照名称进行注入、按照类型进行注入和按照构造方法进行注入
按照名称进行注入
spring容器会按照set属性的名称去容器中查找同名的bean对象,然后将查找到的对象通过set方法注入到对应的bean中,未找到对应名称的bean对象则set方法不进行注入
创建Student和School类
public class Student {
private School school;
private String name;
private String age;
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Student [school=" + school + ", name=" + name + ", age=" + age + "]";
}
}
public class School {
private String address;
private String name;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "School [address=" + address + ", name=" + name + "]";
}
}
编写xml文件
<bean id="sc" class="com.demo.autowire.School">
<property name="address" value="北京"></property>
<property name="name" value="北大"></property>
</bean>
<bean id="mystu" class="com.demo.autowire.Student" autowire="byName">
<property name="age" value="20"></property>
<property name="name" value="张三"></property>
</bean>
byName是根据名字来赋值,所以id名要和参数一致才可,列如此处的Student类中并没有为school属性赋值,我们准备使用byName自动赋值,那么我们在写xml文件的时候给school类的id必须和student类里school的属性名称一样才能完成赋值
测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.demo.autowire.*;
public class Test {
public static void main(String[] args) {
String config = "classpath:spring/ApplicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
Student student = (Student) ac.getBean("mystu");
System.out.println(student);
}
}
结果如图所示赋值成功
按照类型注入
spring容器会遍历x类中所有的set方法,会在容器中查找和set参数类型相同的bean对象,将其通过set方法进行注入,未找到对应类型的bean对象则set方法不进行注入。
需要注入的set属性的类型和被注入的bean的类型需要满足isAssignableFrom关系。
按照类型自动装配的时候,如果按照类型找到了多个符合条件的bean,系统会报错。父子类实现关系都算同种
set方法的参数如果是下面的类型或者下面类型的数组的时候,这个set方法会被跳过注入:
创建Game类和User类
public class User {
private Game game;
private String name;
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [game=" + game + ", name=" + name + "]";
}
}
public class Game {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Game [name=" + name + "]";
}
}
编写xml文件
<bean id="game" class="com.demo.autowire_type.Game">
<property name="name" value="王者荣耀"></property>
</bean>
<!-- byType是按照类型自动赋值,在本例中我们需要自动赋值Game,他就会在xml文件里查找类型为game的,但是同种类型只能存在一个,实现类,父子类都算同种类型
也就是说,在这个xml文件里只可以存在一个game类。他的父子类,实现类都不能存在 -->
<bean id="user" class="com.demo.autowire_type.User" autowire="byType">
<property name="name" value="张三"></property>
</bean>
测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.demo.autowire.*;
public class Test {
public static void main(String[] args) {
String config = "classpath:spring/ApplicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
User user = (User) ac.getBean("user");
System.out.println(user);
}
}
结果
Game类的name被自动赋值了
按照构造自动注入
spring会找到x类中所有的构造方法(一个类可能有多个构造方法),然后将这些构造方法进行排序(先按修饰符进行排序,public的在前面,其他的在后面,如果修饰符一样的,会按照构造函数参数数量倒叙,也就是采用贪婪的模式进行匹配,spring容器会尽量多注入一些需要的对象)得到一个构造函数列表,会轮询这个构造器列表,判断当前构造器所有参数是否在容器中都可以找到匹配的bean对象,如果可以找到就使用这个构造器进行注入,如果不能找到,那么就会跳过这个构造器,继续采用同样的方式匹配下一个构造器,直到找到一个合适的为止。
创建Game类和User类
public class User {
private Game game;
private String name;
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(Game game) {
super();
this.game = game;
}
@Override
public String toString() {
return "User [game=" + game + ", name=" + name + "]";
}
}
public class Game {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Game [name=" + name + "]";
}
}
编写xml文件
<bean id="Game" class="com.demo.autowire_con.Game">
<property name="name" value="王者荣耀"></property>
</bean>
<!-- 构造注入会采用贪婪模式,最大限度地注入属性,即当一个构造要注入三个,一个要注入俩个,会选择第一个 -->
<bean id="user" class="com.demo.autowire_con.User" autowire="constructor">
<property name="name" value="张三"></property>
</bean>
测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.demo.autowire_con.*;
public class Test {
public static void main(String[] args) {
String config = "classpath:spring/ApplicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
User user = (User) ac.getBean("User");
System.out.println(user);
}
}
结果,如图,构造注入赋值成功