依赖注入DI (Dependency Injection):从应用程序的角度描述,创建对象实例时,为这个对象注入属性值或其它对象实例,(依赖于容器注入它所需要的外部资源)。实现
控制反转:从容器的角度描述,创建对象实例的控制权从应用程序,反转到IOC容器控制(在xml文件控制),强调容器的作用。负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入了它依赖的实例,因此控制翻转也可以称之为依赖注入。概念
依赖注入的两种方式
简单数据类型字符串。
1.为实体类添加构造方法
public class User {
private String name;
private String sex;
private int age;
public User(String name, String sex, Integer age) {
this.name = name;
this.sex = sex;
this.age = age;
}
2. 修改配置文件
- constructor-arg标签属性
- name属性:通过参数名找到参数列表中对应参数
- index属性:通过参数在参数列表中的索引找到参数列表中对应参数,index从0开始。
- type属性:通过参数数据类型找到参数列表中对应参数
- value属性:设置参数列表参数对应的值,用于设定基本数据类型和String类型的数据
- ref属性:如果参数值为非基本数据类型,则可通过ref为参数注入值,其值为另一个bean标签id或name属性的属性值
- constructor-arg子标签:
- ref子标签:对应ref属性,该标签name属性的属性值为另一个bean标签id或name属性的属性
- value子标签:对应value属性,用于设置基本数据类型或String类型的参数值;
- list子标签:为数组或List类型的参数赋值
- set子标签:为Set集合类型参数赋值
- map子标签:为Map集合类型参数赋值
- props子标签:为Properties类型的参数赋值
<bean id = "user" class="com.qlit.bean.User">
<constructor-arg name="name" value="张三"/>
<constructor-arg name="sex" value="男"/>
<constructor-arg name="age" value="22"/>
bean>
使用lombok,快速生成常用方法提高开发速度。
idea安装插件
文件➡️设置➡️插件,搜索Lombok
引入依赖
中央仓库地址:https://mvnrepository.com/
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.24version>
<scope>providedscope>
dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private String sex;
private Integer age;
public void sayHello(){
System.out.println("hello");
}
}
@Getter/@Setter: 作用类上,生成所有成员变量的getter/setter方法;
作用于成员变量上,生成该成员变量的getter/setter方法。@ToString: 作用于类,覆盖默认的toString()方法
@EqualsAndHashCode: 作用于类,覆盖默认的equals和hashCode
@NoArgsConstructor生成无参构造器;
@RequiredArgsConstructor生成包含final和@NonNull注解的成员变量的构造器;
@AllArgsConstructor生成全参构造器
@Data: 作用于类上,注解集合,使用它相当于使用下列注解:
- @ToString
- @EqualsAndHashCode
- @Getter
- @Setter
- @RequiredArgsConstructor
@Builder: 作用于类上,将类转变为建造者模式
@Log: 作用于类上,生成日志变量
public class IdCard {
int id;
String code;
}
xml方式一
<bean id="idcard" class="com.yiwu.pojo.IdCard">
<constructor-arg name="id" value="1"/>
<constructor-arg name="code" value="2222222"/>
bean>
<bean id = "user3" class="com.yiwu.pojo.User">
<constructor-arg name="name" value="张三"/>
<constructor-arg name="sex" value="男"/>
<constructor-arg name="age" value="22"/>
<constructor-arg name="idcard" ref="idcard"/>
bean>
xml方式二
<bean id = "user4" class="com.yiwu.pojo.User">
<constructor-arg name="name" value="张三"/>
<constructor-arg name="sex" value="男"/>
<constructor-arg name="age" value="22"/>
<constructor-arg name="idcard">
<bean class="com.yiwu.pojo.IdCard">
<constructor-arg name="id" value="1"/>
<constructor-arg name="code" value="2222222"/>
bean>
constructor-arg>
bean>
实体类中添加private Date brithday属性,并更新构造方法。
方式一
对于dete对象同样利用其构造方法。
<bean id="b" class="java.util.Date">
<constructor-arg name="year" value="10"/>
<constructor-arg name="month" value="11"/>
<constructor-arg name="date" value="2"/>
bean>
<bean id = "user5" class="com.yiwu.pojo.User">
<constructor-arg name="name" value="张三"/>
<constructor-arg name="sex" value="男"/>
<constructor-arg name="age" value="22"/>
<constructor-arg name="brithday" ref="b"/>
bean>
方式二
<bean id = "user6" class="com.yiwu.pojo.User">
<constructor-arg name="name" value="张三"/>
<constructor-arg name="sex" value="男"/>
<constructor-arg name="age" value="22"/>
<constructor-arg name="brithday">
<bean class="java.util.Date">
<constructor-arg name="year" value="10"/>
<constructor-arg name="month" value="10"/>
<constructor-arg name="date" value="2"/>
bean>
constructor-arg>
bean>
List类型
实体类添加private List < String> product;属性,生成对应构造方法(此处仅仅生成了product的构造方法)
如果List集合元素为基本数据类型包装类或String类型,则可通过value标签设置值;如果为其它引用类型的数据则可以通过bean标签或ref标签设置元素值,每对标签设置一个集合元素。
<bean id = "user7" class="com.yiwu.pojo.User">
<constructor-arg name="product">
<list>
<value>aaavalue>
<value>bbbvalue>
list>
constructor-arg>
bean>
Set 类型
用法与list一致,仅需要将xml文件中的list标签改为set标签
Map类型
如果Map集合的值为基本数据类型包装类或String类型,则可通过value属性直接设置;如果为引用类型(如String类型)的数据则可以通过entry 标签的value-ref标签属性(其值为另一个bean标签id或name属性的属性值)或entry 标签bean子标签、ref子标签、list子标签(如果Map集合值为List集合)、set子标签(如果Map集合值为Set集合)或map子标签(如果Map集合值为Map集合)进行设置。
<bean id = "user9" class="com.yiwu.pojo.User">
<constructor-arg name="myMap">
<map>
<entry key="k1" value="aaa"/>
<entry key="k2" value="bbb"/>
<entry key="k3" value="ccc"/>
map>
constructor-arg>
bean>
实体类添加private Properties myProperties属性,添加构造方法,更新toString方法
<bean id = "user10" class="com.yiwu.pojo.User">
<constructor-arg name="myProperties">
<props>
<prop key="key1">aaaprop>
<prop key="key2">aaaprop>
props>
constructor-arg >
bean>
分析:
在 Spring 实例化 Bean 的过程中,IoC 容器首先会调用默认的构造方法(无参构造方法)实例化 Bean(Java 对象),然后通过 Java 的反射机制调用这个 Bean 的 setXxx() 方法,将属性值注入到 Bean 中。
区别:
使用构造函数依赖注入时,Spring保证所有一个对象所有依赖的对象先实例化后,才实例化这个对象。
使用set方法依赖注入时,Spring首先实例化对象,然后才实例化所有依赖的对象。
步骤
简单数据类型字符串。
<bean id = "user11" class="com.yiwu.pojo.User">
<property name="name" value="张三">property>
<property name="sex" value="男">property>
<property name="age" value="22">property>
bean>
<bean name="idcard2" class="com.yiwu.pojo.IdCard">
<property name="code" value="2222222"/>
<property name="id" value="33"/>
bean>
<bean id = "user12" class="com.yiwu.pojo.User">
<property name="name" value="张三"/>
<property name="sex" value="男"/>
<property name="age" value="22"/>
<property name="idcard" ref="idcard2"/>
bean>
<bean id = "user13" class="com.yiwu.pojo.User">
<property name="name" value="张三"/>
<property name="sex" value="男"/>
<property name="age" value="22"/>
<property name="idcard">
<bean class="com.yiwu.pojo.IdCard">
<property name="code" value="2222222"/>
<property name="id" value="33"/>
bean>
property>
bean>
<bean id="b2" class="java.util.Date">
<constructor-arg name="year" value="10"/>
<constructor-arg name="month" value="11"/>
<constructor-arg name="date" value="2"/>
bean>
<bean id = "user14" class="com.yiwu.pojo.User">
<property name="name" value="张三"/>
<property name="sex" value="男"/>
<property name="age" value="22"/>
<property name="brithday" ref="b2"/>
bean>
<bean id = "user15" class="com.yiwu.pojo.User">
<property name="name" value="张三"/>
<property name="sex" value="男"/>
<property name="age" value="22"/>
<property name="brithday">
<bean class="java.util.Date">
<constructor-arg name="year" value="10"/>
<constructor-arg name="month" value="11"/>
<constructor-arg name="date" value="2"/>
bean>
property>
bean>
List
<bean id = "user16" class="com.yiwu.pojo.User">
<property name="product">
<list>
<value>aaavalue>
<value>bbbvalue>
list>
property>
bean>
Set 类型
用法与list一致,仅需要将xml文件中的list标签改为set标签
Map
<bean id = "user17" class="com.yiwu.pojo.User">
<property name="myMap">
<map>
<entry key="k1" value="aaaa"/>
<entry key="k2" value="bbbb"/>
<entry key="k3" value="cccc"/>
map>
property>
bean>
<bean id = "user18" class="com.yiwu.pojo.User">
<property name="myProperties">
<props>
<prop key="key1">aaaprop>
<prop key="key2">aaaprop>
props>
property >
bean>
Spring在实例化当前bean的时候自动从Spring容器中找到匹配的实例赋值给当前bean的属性。
创建应用对象之间协作关系的行为称为装配。也就是说当一个对象的属性是另一个对象时,实例化时,需要为这个对象属性进行实例化。这就是装配
依赖注入的本质就是装配,装配是依赖注入的具体行为,这就是两者的关系
创建Product实体类。,在user中添加 Product pd;
package com.yiwu.pojo;
public class Product {
private String name;
private double Price;
public Product() {
}
}
public class User {
Product pd;
//其余省略,与上节内容不变
}
<bean id = "product1" class="com.yiwu.pojo.Product">
<property name="name" value="java"/>
<property name="price" value="20"/>
bean>
<bean id="user19" class="com.yiwu.pojo.User">
<property name="pd" ref="product1"/>
bean>
根据当前Bean的属性名,在Spring容器中寻找匹配的对象,如果根据Name找到了bean,但是类型不匹配则会抛出异常
bean标签的id值与类的属性名一致
<bean id = "pd" class="com.yiwu.pojo.Product">
<property name="name" value="java"/>
<property name="price" value="20"/>
bean>
<bean id="user19" class="com.yiwu.pojo.User" autowire="byName">
bean>
根据当前Bean的属性类型,在spring容器中寻找匹配的对象,如果根据类型找到了多个类型匹配的bean,也会抛出异常。
<bean id = "pd1" class="com.yiwu.pojo.Product">
<property name="name" value="java"/>
<property name="price" value="20"/>
bean>
<bean id="user19" class="com.yiwu.pojo.User" autowire="byType">
bean>