|

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配置冗余。

依赖注入的核心是“解耦”,让类更专注于自身业务逻辑,而非依赖对象的创建。

posted @ 2025-11-11 18:20  曹轲恒  阅读(0)  评论(0)    收藏  举报