spring DI依赖注入方式和区别有哪些

发布时间:2021-07-29 13:42:11 作者:小新
来源:亿速云 阅读:136
# Spring DI依赖注入方式和区别有哪些

## 目录
1. [依赖注入(DI)核心概念](#一依赖注入di核心概念)
2. [三种主要依赖注入方式](#二三种主要依赖注入方式)
   - [2.1 构造器注入](#21-构造器注入)
   - [2.2 Setter方法注入](#22-setter方法注入)
   - [2.3 字段注入](#23-字段注入)
3. [其他特殊注入方式](#三其他特殊注入方式)
   - [3.1 接口注入](#31-接口注入)
   - [3.2 方法注入](#32-方法注入)
4. [不同注入方式的对比分析](#四不同注入方式的对比分析)
5. [Spring官方推荐实践](#五spring官方推荐实践)
6. [实际开发中的选择策略](#六实际开发中的选择策略)
7. [常见问题与解决方案](#七常见问题与解决方案)

---

## 一、依赖注入(DI)核心概念

依赖注入(Dependency Injection)是Spring框架实现控制反转(IoC)的核心机制,通过将对象依赖关系的创建和管理从代码内部转移到外部容器,实现组件间的解耦。

**核心价值**:
- 降低耦合度
- 提高可测试性
- 增强代码可维护性
- 简化复杂对象创建

```java
// 传统方式(紧耦合)
class ServiceA {
    private ServiceB serviceB = new ServiceB();
}

// DI方式(松耦合)
class ServiceA {
    private ServiceB serviceB;
    // 通过外部注入依赖
    public ServiceA(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

二、三种主要依赖注入方式

2.1 构造器注入

实现方式

@Component
public class OrderService {
    private final PaymentService paymentService;
    
    @Autowired // Spring 4.3+ 可省略
    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

特点: - 强依赖性保障(对象创建时即完成注入) - 适合必须依赖项 - 天然支持不可变对象(final字段) - 明确的循环依赖检测

XML配置等效形式

<bean id="orderService" class="com.example.OrderService">
    <constructor-arg ref="paymentService"/>
</bean>

2.2 Setter方法注入

实现方式

@Component
public class UserService {
    private UserRepository userRepository;
    
    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

特点: - 灵活性高(可重新注入) - 适合可选依赖项 - 支持JavaBean规范 - 可通过@Required注解标记必需依赖

XML配置等效形式

<bean id="userService" class="com.example.UserService">
    <property name="userRepository" ref="userRepository"/>
</bean>

2.3 字段注入

实现方式

@Component
public class ProductService {
    @Autowired
    private InventoryService inventoryService;
}

特点: - 代码简洁(最少样板代码) - 存在反射性能开销 - 难以进行单元测试(必须通过Spring容器) - 隐藏依赖关系


三、其他特殊注入方式

3.1 接口注入(已淘汰)

早期Spring版本通过实现特定接口完成注入,现已被注解方式取代。

3.2 方法注入

@Component
@Scope("prototype")
public class ReportGenerator {
    public void generate(ReportData data) {
        // ...
    }
}

@Component
public class ReportService {
    @Autowired
    private Provider<ReportGenerator> reportGeneratorProvider;
    
    public void createReport() {
        ReportGenerator generator = reportGeneratorProvider.get();
        generator.generate(new ReportData());
    }
}

适用场景: - 解决原型Bean注入单例Bean问题 - 延迟获取Bean实例


四、不同注入方式的对比分析

特性 构造器注入 Setter注入 字段注入
不可变性支持 ✅ (final)
循环依赖检测 立即 延迟 延迟
单元测试便利性 高(可直接new) 低(需反射)
代码简洁度
依赖必要性表达 明确 需额外注解 不明确
Spring官方推荐度 首选 次要选择 不推荐
适合场景 强依赖 可选依赖/配置 快速原型开发

性能影响: - 构造器注入:启动时一次性解决,运行时无开销 - Setter注入:可能存在动态代理开销 - 字段注入:反射操作带来轻微性能损耗


五、Spring官方推荐实践

  1. Spring 4.3+ 自动推断:单构造器时可省略@Autowired

    @Service
    public class TaxService {
       private final Calculator calculator;
    
    
       // 自动识别为注入点
       public TaxService(Calculator calculator) {
           this.calculator = calculator;
       }
    }
    
  2. 必要依赖使用构造器

    @RestController
    public class PaymentController {
       private final PaymentValidator validator;
    
    
       public PaymentController(PaymentValidator validator) {
           Assert.notNull(validator, "Validator must not be null");
           this.validator = validator;
       }
    }
    
  3. 可选依赖使用Setter

    @Service
    public class NotificationService {
       private EmailSender emailSender;
    
    
       @Autowired(required = false)
       public void setEmailSender(EmailSender emailSender) {
           this.emailSender = emailSender;
       }
    }
    

六、实际开发中的选择策略

推荐组合方案: 1. 核心业务组件:构造器注入 2. 基础设施组件:Setter注入 3. 测试类/临时代码:字段注入(需配合@Mock)

循环依赖解决方案

// 方案1:改用Setter注入
@Service
public class ServiceA {
    private ServiceB serviceB;
    
    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

// 方案2:@Lazy延迟初始化
@Service
public class ServiceX {
    private final ServiceY serviceY;
    
    public ServiceX(@Lazy ServiceY serviceY) {
        this.serviceY = serviceY;
    }
}

七、常见问题与解决方案

Q1:该用@Autowired还是@Resource? - @Autowired:按类型装配,支持Spring的@Qualifier - @Resource:JSR-250标准,优先按名称匹配

Q2:多实现类如何注入?

@Autowired
private List<Validator> validators; // 收集所有实现

@Autowired
@Qualifier("primaryDataSource")
private DataSource dataSource;

Q3:测试时如何模拟依赖?

// 构造器注入的测试样例
class OrderServiceTest {
    @Test
    void testCreateOrder() {
        PaymentService mockPayment = mock(PaymentService.class);
        OrderService service = new OrderService(mockPayment);
        // 测试逻辑...
    }
}

最佳实践总结:在Spring Boot应用中,80%的场景应使用构造器注入,15%使用Setter注入,剩余5%特殊场景可考虑字段注入。保持代码的明确性和可测试性应是首要考虑因素。 “`

推荐阅读:
  1. Spring之IOC
  2. Spring3.0第二讲:什么是IOC

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring di

上一篇:VBS中怎么获取当前日期的前一天

下一篇:怎么用C语言实现五子棋游戏

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》