全网疯传的Spring学习笔记【注入】,看完我也想写一个了!
三、注入
3.1、什么是注入
注入是指 Spring 创建对象的过程中,将对象依赖属性通过配置设值给该对象。
3.2、为什么需要注入
通过编码的方式(setXxx),为成员变量进行赋值,存在耦合。
3.3、注入的方式
- set注入:其类必须提供对应 setter 方法。
- 构造器注入:利用构造器进行注入。
3.4、set注入
package com.domain;
/**
* @author Xiao_Lin
* @date 2021/2/4 15:57
*/
public class Person {
private String username;
private Integer password;
@Override
public String toString() {
return "Person{" +
"username='" + username + '\'' +
", password=" + password +
'}';
}
public Person(String username, Integer password) {
this.username = username;
this.password = password;
}
public Person() {
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getPassword() {
return password;
}
public void setPassword(Integer password) {
this.password = password;
}
}
<bean id="person" class="com.domain.Person">
<property name="username">
<value>Xiao_Lin</value>
</property>
<property name="password">
<value>123456</value>
</property>
</bean>
/**
* 用于测试注入
*/
@Test
public void testDI(){
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = application.getBean("person", Person.class);
System.out.println(person);
}
3.4.1、set注入的原理图
Spring通过底层调用对象属性对应的set方法完成对成员变量的赋值操作。
3.4.2、set注入详解
针对不同的不同类型的成员变量,我们不可能一直是使用value
标签,我们需要嵌套其他的标签,我们将成员变量可能的类型分类两大类:
- JDK内置类型。
- 用户自定义类型。
3.4.2.1、JDK内置类型
3.4.2.1.1、String+8种基本数据类型
都直接使用value
标签即可
<property name="password">
<value>123456</value>
</property>
3.4.2.1.2、数组类型
对于数组类型,我们需要在配置文件中,使用list
标签,表明是数组类型,嵌套value
标签来进行赋值。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private String[] emails;
}
<property name="emails">
<list>
<value>124@qq.com</value>
<value>456@163.com</value>
</list>
</property>
3.4.2.1.3、Set集合
对于set集合类型,我们需要在配置文件中,使用set
标签,表明是set
集合类型,嵌套Set泛型中对应的标签来进行赋值。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private Set<String> tels;
}
<property name="tels">
<set>
<value>123456</value>
<value>456789</value>
<value>13579</value>
</set>
</property>
对于set集合由于我们规范了泛型为String,她是8种基本数据类型,所以在set标签中才嵌套value标签。如果没有规定泛型或者说是规定了其他的泛型,set嵌套的标签需要根据具体的情况来具体分析。
3.4.2.1.4、List集合
对于List集合类型,我们需要在配置文件中,使用list
标签,表明是List集合类型,嵌套List泛型中对应的标签来进行赋值。
list便签中嵌套什么标签,取决于List集合中的泛型。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private List<String> address;
}
<property name="address">
<list>
<value>sz</value>
<value>sz</value>
<value>gz</value>
</list>
</property>
3.4.2.1.5、Map集合
对于Map集合,有一个内部类——Entry,所以我们在配置文件中需要使用的标签是用map
标签来嵌套entry
标签,里面是封装了一对键值对。我们使用key
标签来表示键,里面嵌套键对应的标签,值要根据对应的类型来选择对应的标签。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private Map<String,String> qq;
}
<property name="qq">
<map>
<entry>
<key><value>zs</value></key>
<value>123456</value>
</entry>
<entry>
<key><value>lisi</value></key>
<value>456789</value>
</entry>
</map>
</property>
3.4.2.1.6、Properties集合
Properties类似是特殊的Map,他的key
和value
都必须是String
类型。
在配置文件中,我们使用props
标签,里面嵌套prop
标签,一个prop
就是一个键值对,键写在key
属性中,值写在标签内部。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private Properties properties;
}
<property name="properties">
<props>
<prop key="username">admin</prop>
<prop key="password">123456</prop>
</props>
</property>
3.4.2.2、自定义类型
3.4.2.2.1、第一种注入方式
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Hobby {
private String name;
}
<property name="hobby">
<bean class="com.domain.Hobby"/>
</property>
我们可以发现第一种注入方式其实就是在property
标签里面写一个bean
标签,他的劣势也很明显:
- 配置文件代码冗余,我有一万个类需要引用同一个对象的时候,我同一段代码需要写一万次。
- 被注入的对象,被多次创建,浪费(JVM)内存资源,因为我每写一个
bean
标签意味着就创建一个新的对象。
3.4.2.2.2、第二种注入方式
鉴于第一种注入方式的缺点很明显,我们就需要改进,于是就有了第二种注入方式,这种方式是将我们需要注入的对象提前先创建一份出来,谁需要谁去引用即可。
<bean>
<property name="hobby">
<ref bean="hobby"/>
</property>
</bean>
<bean id="hobby" class="com.domain.Hobby">
<property name="name">
<value>admin</value>
</property>
</bean>
3.4.3、set注入的简化写法
3.4.3.1、基于属性的简化
JDK类型注入
我们可以使用value
属性来简化value
标签的值,但是只可以简化8种基本数据类型➕Stirng类型的值。
<!--以前的方式-->
<property name="name">
<value>Xiao_Lin</value>
</property>
<!--简化后的方式-->
<property name="name" value="Xiao_Lin"/>
用户自定义类型的注入
我们可以使用ref属性来简化ref
标签的值.
<!--以前的方式-->
<property name="hobby">
<ref bean="hobby"/>
</property>
<!--简化后的方式-->
<property name="hobby" ref="hobby"/>
3.4.3.2、基于p命名空间的简化
我们可以发现,bean
标签的很多值都是重复且冗余的,于是可以使用p
命名空间来进行简化。
<!--内置数据类型-->
<bean id="person" class="com.domain.Person" p:username="zs" p:password="123456" />
<!--用户自定义类型-->
<bean id="hobbyBean" class="com.domain.Hobby"></bean>
<bean id="hobby" class="com.domain.Person" p:hobby-ref="hobbyBean"
3.5、构造注入
Spring调用构造方法,通过配置文件为成员变量赋值。如果要使用构造注入,必须提供有参的构造方法。
构造注入使用的标签是constructor-arg
标签,一个构造参数就是一对constructor-arg
标签。顺序和个数都必须和构造参数一样。
当出现构造方法重载的时候,我们可以通过控制constructor-arg
的个数来进行控制。如果出现构造参数个数相同的重载的时候(如第一个构造方法是给name赋值,第二个构造方法给type赋值),我们需要用type
属性来指定类型。
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Hobby {
private String name;
private String type;
}
<bean id="hobbyBean" class="com.domain.Hobby">
<constructor-arg>
<value>running</value>
</constructor-arg>
<constructor-arg>
<value>dayily</value>
</constructor-arg>
</bean>
/**
* 用于测试构造注入
*/
@Test
public void testDI2(){
ClassPathXmlApplicationContext cxt =
new ClassPathXmlApplicationContext("/applicationContext.xml");
Hobby hobbyBean = cxt.getBean("hobbyBean", Hobby.class);
System.out.println(hobbyBean);
}
3.6、注入总结
- 点赞
- 收藏
- 关注作者
评论(0)