spring的注入方式都有什么区别

目录

[1. 构造器注入(Constructor Injection)](#1. 构造器注入(Constructor Injection))

[2. Setter 注入(Setter Injection)](#2. Setter 注入(Setter Injection))

[3. 字段注入(Field Injection)](#3. 字段注入(Field Injection))

[4. 接口注入(Interface Injection)](#4. 接口注入(Interface Injection))

主要区别对比

最佳实践

总结

1. 构造器注入(Constructor Injection)

  • 方式:通过构造方法完成依赖注入。

  • 配置

    • XML :使用 <constructor-arg> 标签。
    • Java 注解 :使用 @Autowired 或隐式构造器(Spring 4.3+)。
  • 示例

    java

    java 复制代码
    @RequiredArgsConstructor
    public class UserService {
        private final UserRepository userRepository;
    
        // 构造器注入(Spring 4.3+ 可省略 @Autowired)
        /*@Autowired
        public UserService(UserRepository userRepository) {
            this.userRepository = userRepository;
        }*/
    }
  • 特点

    • 不可变依赖 :依赖对象在创建后不可变(final 字段)。
    • 强制依赖:对象创建时必须提供所有依赖,避免空指针异常。
    • 防止循环依赖:Spring 会在启动时检测并报错。
  • 适用场景

    • 强制依赖的场景(如核心业务组件)。
    • 不可变对象(如使用 final 字段)。

2. Setter 注入(Setter Injection)

  • 方式:通过公共的 Setter 方法完成依赖注入。

  • 配置

    • XML :使用 <property> 标签。
    • Java 注解 :使用 @Autowired@Inject
  • 示例

    java

    java 复制代码
    public class UserService {
        private UserRepository userRepository;
    
        // Setter 注入
        @Autowired
        public void setUserRepository(UserRepository userRepository) {
            this.userRepository = userRepository;
        }
    }
  • 特点

    • 可选依赖:依赖可以在对象创建后通过 Setter 方法设置。
    • 灵活性高:适合动态修改依赖(如配置参数)。
    • 可能存在空指针风险:需确保使用前依赖已注入。
  • 适用场景

    • 可选依赖的场景(如配置参数)。
    • 需要动态修改依赖的场景。

3. 字段注入(Field Injection)

  • 方式:通过反射直接注入私有字段。

  • 配置 :使用 @Autowired@Resource@Inject 注解。

  • 示例

    java

    java 复制代码
    public class UserService {
        @Autowired
        private UserRepository userRepository;
    }
  • 特点

    • 代码简洁:无需构造器或 Setter 方法。
    • 依赖隐藏:依赖关系不明确(如无法从构造器看出)。
    • 仅适用于 Spring 容器:不利于单元测试(需使用反射注入)。
  • 适用场景

    • 简单组件(如工具类、控制器)。
    • 快速开发或遗留代码。

4. 接口注入(Interface Injection)

  • 方式:通过实现特定接口来声明依赖。

  • 特点

    • 侵入性强 :组件需实现 Spring 特定接口(如 ApplicationContextAware)。
    • 已过时:现代 Spring 项目很少使用。
  • 示例

    java

    java 复制代码
    public class MyComponent implements ApplicationContextAware {
        private ApplicationContext context;
    
        @Override
        public void setApplicationContext(ApplicationContext context) {
            this.context = context;
        }
    }

主要区别对比

特性 构造器注入 Setter 注入 字段注入
依赖强制性 强制(必须提供) 可选(可后设置) 强制(运行时注入)
不可变性 支持(final 字段) 不支持 不支持
循环依赖检测 启动时检测 运行时可能出错 运行时可能出错
单元测试难度 低(可手动创建) 中(需调用 Setter) 高(需反射或 Mock)
依赖可见性 明确(构造器参数) 较明确(Setter 方法) 隐藏(字段注解)
适用场景 核心组件、不可变依赖 可选依赖、动态配置 简单组件、快速开发

最佳实践

  1. 优先使用构造器注入

    • 确保依赖不可变且强制注入。
    • 符合单一职责原则和依赖倒置原则。
  2. 使用 Setter 注入处理可选依赖

    • 例如配置参数、可替换的组件。
  3. 谨慎使用字段注入

    • 仅在无法使用构造器或 Setter 时(如框架限制)使用。
    • 避免在需要测试的组件中使用。
  4. 避免接口注入

    • 耦合度高,不符合现代开发实践。

总结

构造器注入和 Setter 注入是最常用的方式,选择时需根据依赖的性质(强制 / 可选、可变 / 不可变)和组件的设计目标来决定。字段注入虽然简洁,但存在测试困难和依赖隐藏的问题,应谨慎使用。

相关推荐
兰令水1 天前
leecodecode【面试150】【2026.6.14打卡-java版本】
java·算法·面试
yaoxin5211231 天前
434. Java 日期时间 API - Period 基于日期的时间段
java·开发语言·python
何极光1 天前
IDEA集成Maven
java·maven·intellij-idea
程序员二叉1 天前
【JUC】ThreadLocal底层原理|内存泄漏|弱引用|跨线程传递方案
java·开发语言·面试·职场和发展·juc
程序员二叉1 天前
【JUC】线程池全套深度详解|参数|流程|拒绝策略|调优|异常处理
java·开发语言·jvm·算法·面试·juc
老马识途2.01 天前
在AI的帮助下理解spring的启动过程
java·前端·spring
青山木1 天前
Hot 100 --- 轮转数组
java·数据结构·算法
Qt程序员1 天前
掌握 Linux 内核调度:从原理到实现(进程篇)
java·开发语言
code bean1 天前
【LangChain】检索器完全指南:从向量检索到生产级 RAG 架构
java·开发语言·微服务
大白菜和MySQL1 天前
java应用排查高线程
java·python