- 注入: Spring通过
配置文件
,为成员变量赋值; - Set注入:Spring调用
Set方法
通过配置文件
为成员变量赋值; - 构造注入:Spring调用
构造方法
通过配置文件
为成员变量赋值;
文章目录
一、注入(Injection)
-
什么是注入?
通过 Spring 工厂及配置文件,为所创建对象的成员变量赋值。 -
为什么要注入?
注入的好处:解耦合。因为通过编码的方式,为成员变量进行赋值,存在耦合。
public void test() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
Person person = (Person) ctx.getBean("person");
// 通过代码为变量赋值, 存在耦合, 如果我们以后想修改变量的值, 需要修改代码, 重新编译
person.setId(1);
person.setName("zhenyu");
System.out.println(person);
}
二、简单注入实现
- 类的成员变量提供 set get 方法
- 配置 spring 的配置文件
<bean id="c" class="com.zqc.bean.Account">
<property name="id" value="10"/>
<property name="name" value="ZQC"/>
</bean>
简易原理分析:
通过Spring工厂创建类的时候,在配置文件中有这个类的默认属性,Spring的底层通过调用该实体类的set方法,可将配置文件中的属性值赋予这个对象,这种方式称为Set注入。
所以,“Spring工厂 + 配置文件” 实现了 “空参构造器 + set方法赋值”。
三、Set注入
Set注入的变量类型:
- JDK内置类型
8种基本类型 + String、数组类型、set集合、list集合、Map集合、Properties集合。 - 用户自定义类型
针对于不同类型的成员变量,在<property>
标签中,需要嵌套其他标签:
<property>
xxxxx
</property>
3.1 JDK内置类型
- String+8种基本类型
<property name="id">
<value>10</value>
</property>
<property name="name">
<value>ZQC</value>
</property>
<!--或则这种形式-->
<property name="id" value="10"/>
<property name="name" value="ZQC"/>
- 数组
<property name="emails">
<list>
<value>abc@qq.com</value>
<value>123@qq.com</value>
<value>hello@qq.com</value>
</list>
</property>
- Set集合
<property name="tels">
<set>
<value>138xxxxxxxxxx</value>
<value>139xxxxxxxxxx</value>
<value>138xxxxxxxxxx</value><!--set会自动去重-->
</set>
</property>
- List集合
<property name="addresses">
<list>
<value>China</value>
<value>Earth</value>
<value>hell</value>
</list>
</property>
- Map集合
<property name="qqs">
<map>
<entry>
<key><value>hello</value></key>
<value>12312312312</value>
</entry>
<entry>
<key><value>world</value></key>
<value>21314214214</value>
</entry>
</map>
</property>
- Properites
<property name="p">
<props>
<prop key="key1">value1</prop>
<prop key="key2">value2</prop>
<prop key="key3">value3</prop>
</props>
</property>
3.2 用户自定义类型
方式1
- 为成员变量提供 set get 方法
- 配置文件中进行注入(赋值)
<bean id="userService" class="com.yusael.service.UserServiceImpl">
<property name="userDAO">
<bean class="com.yusael.dao.UserDAOImpl"/>
</property>
</bean>
- 存在问题:
配置文件代码冗余;
被注入的对象 (UserDAO)多次创建,浪费(JVM)内存资源。
方式2
- 为成员变量提供 set get 方法;
- 配置文件中进行配置;
<bean id="userDAO" class="com.yusael.dao.UserDAOImpl"></bean>
<bean id="userService" class="com.yusael.service.UserServiceImpl">
<property name="userDAO">
<ref bean="userDAO"/>
</property>
</bean>
Spring4.x 废除了 <ref local=""/>
基本等效 <ref bean=""/>
;
3.3 Set注入的简化
3.3.1 基于属性的简化
- JDK类型注入简化
<property name="id">
<value>10</value>
</property>
👇👇👇
<property name="id" value="10"/>
value 属性只能简化 8种基本类型 + String 注入标签;
- 用户自定义类型注入简化:
<bean id="userDAO" class="com.zqc.dao.UserDAOImpl"></bean>
<bean id="userService" class="com.zqc.service.UserServiceImpl">
<property name="userDAO">
<ref bean="userDAO"/>
</property>
</bean>
👇👇👇
<bean id="userDAO" class="com.zqc.dao.UserDAOImpl"></bean>
<bean id="userService" class="com.zqc.service.UserServiceImpl">
<property name="userDAO" ref="userDAO"/>
</bean>
3.3.2 基于p命名空间的简化
- JDK 类型注入
<bean id="person" name="p" class="com.yusael.basic.Person">
<property name="id">
<value>10</value>
</property>
<property name="name">
<value>yusael</value>
</property>
</bean>
👇👇👇
<bean id="person" name="p" class="com.zqc.basic.Person" p:name="ZQC" p:id="10"/>
- 用户自定义类型注入
<bean id="userDAO" class="com.yusael.dao.UserDAOImpl"></bean>
<bean id="userService" class="com.yusael.service.UserServiceImpl">
<property name="userDAO">
<ref bean="userDAO"/>
</property>
</bean>
👇👇👇
<bean id="userDAO" class="com.yusael.dao.UserDAOImpl"></bean>
<bean id="userService" class="com.yusael.service.UserServiceImpl" p:userDAO-ref="userDAO"/>
四、构造注入
4.1 有参构造注入
提供有参构造方法
public class Customer {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
spring 配置文件
<bean id="customer" class="com.yusael.constructor.Customer">
<constructor-arg>
<value>zhenyu</value>
</constructor-arg>
<constructor-arg>
<value>21</value>
</constructor-arg>
</bean>
4.2 构造方法重载
参数个数不同时,通过控制 <constructor-arg>
标签的数量进行区分;
如果只有一个参数的话,只需要一对 <constructor-arg>
标签:
<bean id="customer" class="com.yusael.constructor.Customer">
<constructor-arg>
<value>zqc</value>
</constructor-arg>
</bean>
如果有两个参数的话,用两对 <constructor-arg>
标签,以此类推。
<bean id="customer" class="com.yusael.constructor.Customer">
<constructor-arg>
<value>zqc</value>
</constructor-arg>
<constructor-arg>
<value>22</value>
</constructor-arg>
</bean>
构造参数个数相同时,通过在标签引入type
属性进行类型的区分<constructor-arg type="">
<bean id="customer" class="com.yusael.constructor.Customer">
<constructor-arg type="int">
<value>20</value>
</constructor-arg>
</bean>
五、总结
未来的实战中,应用 set注入 还是 构造注入?
答:set 注入更多。因为构造注入麻烦(重载),Spring 框架底层大量应用了set注入。
参考:
孙哥说Spring5
https://blog.csdn.net/weixin_43734095/article/details/106264365