DI依赖注入
依赖注入(Dependency Injection)
依赖注入(DI)是控制反转(IoC)的一种实现方式,核心思想是:将类所依赖的对象通过外部注入,而非类内部自行创建,从而降低类之间的耦合度。简单来说,就是“给某个类中的属性赋值”,但赋值过程由外部容器(如Spring)管理。
依赖注入的常见方式
1. 构造器注入
通过类的构造方法传递依赖对象,容器在创建对象时调用构造器并传入所需的依赖。
适用场景:依赖必须存在(不可缺省),且创建后不允许修改的场景。
代码示例:
// 被依赖的类
public class UserDao {
public void addUser() {
System.out.println("添加用户到数据库");
}
}
// 依赖注入的类(通过构造器注入UserDao)
public class UserService {
private UserDao userDao;
// 构造器注入:通过构造方法接收依赖
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void register() {
userDao.addUser(); // 使用注入的依赖
}
}
// Spring配置文件(applicationContext.xml)
<bean id="userDao" class="com.example.UserDao"/>
<bean id="userService" class="com.example.UserService">
<!-- 构造器注入:通过name指定构造方法参数名,ref引用其他bean -->
<constructor-arg name="userDao" ref="userDao"/>
</bean>
2. Set方法注入
通过类的setter方法为属性赋值,容器在创建对象后调用set方法注入依赖。
适用场景:依赖可选(可缺省),或需要在对象创建后动态修改依赖的场景。
支持的注入类型:
- 基本数据类型(int、String等)
- 引用数据类型(其他Bean)
- 集合类型(List、Map、Set等)
代码示例:
public class OrderService {
// 基本类型属性
private String serviceName;
private int maxOrderCount;
// 引用类型属性
private UserDao userDao;
// 集合类型属性
private List<String> orderTypes;
private Map<String, Integer> orderLimits;
// Setter方法(用于注入)
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public void setMaxOrderCount(int maxOrderCount) {
this.maxOrderCount = maxOrderCount;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setOrderTypes(List<String> orderTypes) {
this.orderTypes = orderTypes;
}
public void setOrderLimits(Map<String, Integer> orderLimits) {
this.orderLimits = orderLimits;
}
// 测试方法
public void showInfo() {
System.out.println("服务名称:" + serviceName);
System.out.println("最大订单数:" + maxOrderCount);
System.out.println("关联的UserDao:" + userDao);
System.out.println("订单类型:" + orderTypes);
System.out.println("订单限额:" + orderLimits);
}
}
// Spring配置文件(applicationContext.xml)
<bean id="userDao" class="com.example.UserDao"/>
<bean id="orderService" class="com.example.OrderService">
<!-- 基本类型注入 -->
<property name="serviceName" value="订单服务"/>
<property name="maxOrderCount" value="100"/>
<!-- 引用类型注入(ref指向其他bean) -->
<property name="userDao" ref="userDao"/>
<!-- 集合类型注入 -->
<property name="orderTypes">
<list>
<value>普通订单</value>
<value>秒杀订单</value>
</list>
</property>
<property name="orderLimits">
<map>
<entry key="普通订单" value="50"/>
<entry key="秒杀订单" value="10"/>
</map>
</property>
</bean>
3. 命名空间注入(c命名和p命名)
通过XML命名空间简化注入配置,本质是构造器注入和set方法注入的语法糖。
(1)p命名空间注入(对应set方法注入)
- 需在XML中声明命名空间:
xmlns:p="http://www.springframework.org/schema/p" - 语法:
p:属性名="值"(基本类型)或p:属性名-ref="beanId"(引用类型)
代码示例:
<!-- 声明p命名空间 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.example.UserDao"/>
<!-- p命名空间注入(等价于set方法注入) -->
<bean id="orderService" class="com.example.OrderService"
p:serviceName="订单服务"
p:maxOrderCount="100"
p:userDao-ref="userDao"/> <!-- 引用类型用-ref -->
</beans>
(2)c命名空间注入(对应构造器注入)
- 需在XML中声明命名空间:
xmlns:c="http://www.springframework.org/schema/c" - 语法:
c:参数名="值"(基本类型)或c:参数名-ref="beanId"(引用类型)
代码示例:
<!-- 声明c命名空间 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.example.UserDao"/>
<!-- c命名空间注入(等价于构造器注入) -->
<bean id="userService" class="com.example.UserService"
c:userDao-ref="userDao"/> <!-- 构造方法参数名为userDao -->
</beans>
总结
- 构造器注入:通过构造方法传递依赖,适合必填依赖。
- Set方法注入:通过setter方法赋值,支持多种数据类型,适合可选依赖。
- 命名空间注入:c命名(构造器)和p命名(set方法)的简化语法,减少XML配置冗余。
依赖注入的核心是“解耦”,让类更专注于自身业务逻辑,而非依赖对象的创建。

浙公网安备 33010602011771号