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

相关推荐
未若君雅裁4 分钟前
MyBatis 一级缓存、二级缓存与清理机制
java·缓存·mybatis
AI人工智能+电脑小能手31 分钟前
【大白话说Java面试题 第65题】【JVM篇】第25题:谈谈对 OOM 的认识
java·开发语言·jvm
阿维的博客日记1 小时前
Nacos 为什么能让配置动态生效?(涉及 @RefreshScope 注解)
java·spring
雨辰AI1 小时前
SpringBoot3 + 人大金仓读写分离 + 分库分表 + 集群高可用 全栈实战
java·数据库·mysql·政务
辰海Coding2 小时前
MiniSpring框架学习-完成的 IoC 容器
java·spring boot·学习·架构
小小编程路2 小时前
C++ 多线程与并发
java·jvm·c++
AI视觉网奇3 小时前
linux 检索库 判断库是否支持
java·linux·服务器
她的男孩3 小时前
从零搭一个企业后台,为什么我把能力拆成 Starter 和 Plugin
java·后端·架构
RainCity3 小时前
Java Swing 自定义组件库分享(七)
java·笔记·后端
Sam_Deep_Thinking3 小时前
连锁门店的外卖订单平台对接
java·微服务·架构·系统架构