当前位置: 首页 > article >正文

Spring 中注入 Bean 的方式推荐

在 Spring 中,注入 Bean 的方式有多种,每种方式适用于不同的场景。一般来说,可以选择以下几种注入方式:构造器注入setter 注入字段注入(即使用 @Autowired)以及基于注解的注入(如 @Qualifier)。每种方式都有其优缺点,下面是对每种方式的分析,并给出推荐的最佳实践。

1. 构造器注入(推荐方式)

构造器注入是通过构造函数来注入依赖的方式,它是最为推荐的注入方式,具有以下优点:

  • 明确依赖关系:构造器注入可以强制所有必需的依赖在对象创建时就被注入,这有助于避免对象处于不完整状态(即未注入依赖的状态)。
  • 更容易进行单元测试:构造器注入可以确保依赖在创建时就被注入,因此在进行单元测试时,可以轻松地将依赖注入到构造函数中,便于进行 Mock。
  • 不可变性:通过构造器注入,依赖关系通常是不可变的,有助于提高对象的稳定性。
@Component
public class MyService {
    private final MyRepository myRepository;

    @Autowired
    public MyService(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    public void serve() {
        System.out.println("Service using " + myRepository);
    }
}

总结

  • 优点:强制依赖注入,确保对象在创建时完整,适合需要确保所有依赖的场景。
  • 推荐使用:对于所有必需的依赖,优先使用构造器注入。

2. Setter 注入(次选)

Setter 注入是通过 setter 方法来注入依赖。Spring 会在 Bean 创建后调用 setter 方法来注入依赖。

  • 灵活性:可以选择性地注入某些依赖。
  • 不强制依赖:与构造器注入不同,setter 注入是可选的,不强制所有依赖都必须被注入,可能会导致依赖项没有被注入,从而导致潜在的 NullPointerException
  • 适用于可选依赖:对于那些可以不注入的依赖,使用 setter 注入较为合适。
@Component
public class MyService {
    private MyRepository myRepository;

    @Autowired
    public void setMyRepository(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    public void serve() {
        System.out.println("Service using " + myRepository);
    }
}

总结

  • 优点:灵活性较高,适用于那些依赖关系可选的场景。
  • 推荐使用:对于可选的依赖,使用 setter 注入。

3. 字段注入(不推荐,除非必须)

字段注入是通过直接在字段上使用 @Autowired 注解来注入依赖。Spring 会在创建 Bean 时直接注入字段。这种方式简单,但也有一些明显的缺点。

  • 不易测试:字段注入直接操作类的字段,无法通过构造器或 setter 进行手动注入,导致在单元测试中难以模拟依赖。
  • 不可控性:字段注入导致依赖关系不明确,不能像构造器注入那样保证对象创建时一定处于完整状态。
  • 不推荐使用:字段注入不如构造器和 setter 注入明确和清晰,通常不推荐在应用程序中使用。
@Component
public class MyService {
    @Autowired
    private MyRepository myRepository;

    public void serve() {
        System.out.println("Service using " + myRepository);
    }
}

总结

  • 优点:代码简洁,易于实现。
  • 缺点:不适合严格要求测试和依赖明确的场景。
  • 推荐使用:尽量避免使用,除非你对注入的依赖非常宽松,且不介意难以进行单元测试。

4. 使用 @Qualifier 区分多个同类型 Bean

当有多个相同类型的 Bean 时,Spring 可能无法确定注入哪一个。此时可以使用 @Qualifier 来明确指定注入的 Bean。

  • 常见应用:适用于同类型但功能不同的多个 Bean,例如有多个 DataSource 或多个服务实现类。
  • 避免冲突:使用 @Qualifier 可以明确指明应该注入哪一个 Bean,避免 Spring 抛出 NoUniqueBeanDefinitionException 异常。
@Component
@Qualifier("myService1")
public class MyService1 implements MyService {
    public void serve() {
        System.out.println("Service 1");
    }
}

@Component
@Qualifier("myService2")
public class MyService2 implements MyService {
    public void serve() {
        System.out.println("Service 2");
    }
}

@Component
public class Consumer {
    private final MyService myService;

    @Autowired
    public Consumer(@Qualifier("myService1") MyService myService) {
        this.myService = myService;
    }

    public void serve() {
        myService.serve();
    }
}

总结

  • 优点:解决了同类型 Bean 注入冲突的问题。
  • 推荐使用:在同类型 Bean 存在时,通过 @Qualifier 来避免冲突。

结论

  • 首选:构造器注入,因为它提供了强依赖、清晰的依赖关系、便于测试且更具可维护性。
  • 次选:Setter 注入,适合可选依赖的场景,但在生产环境中通常还是偏好构造器注入。
  • 避免使用:字段注入,因为它减少了依赖关系的明确性,且测试起来不方便。

总的来说,尽量在 Spring 中使用 构造器注入,只有在特殊情况下(如依赖关系是可选的)才使用 setter 注入


http://www.kler.cn/a/465158.html

相关文章:

  • cursor 配置 deepseek 后,无法使用 cursor 的 Composer问题
  • pandas-栗子
  • 25.1.3
  • Spring Boot自定义Starter
  • kubelet状态错误报错
  • 关于 PPPOE技术的详细解释
  • 【three.js】搭建环境
  • 详细讲一下React中Redux的持久化存储(Redux-persist)
  • 分析服务器 systemctl 启动gozero项目报错的解决方案
  • bilibili 哔哩哔哩小游戏SDK接入
  • 黑马商城:RabbitMQ基础
  • 在K8S中,Pod请求另一个Pod偶尔出现超市或延迟,如何排查?
  • 试题转excel;word转excel;大风车excel(1.1更新)
  • Linux 系统常见问题
  • sklearn_pandas.DataFrameMapper的用法
  • [算法] [leetcode-215] 数组中的第K个最大元素
  • wx015基于springboot+vue+uniapp的经济新闻资讯的设计与实现
  • 虚拟电厂搭建指南:绿虫仿真设计软件的助力
  • 【MySQL】什么是事务?MVCC?
  • Ceph对象存储接口的路线
  • 直观解读 JuiceFS 的数据和元数据设计(一)
  • LWM2M---Wakaama源码对接华为云平台
  • 推荐几个 docker 镜像加速地址
  • 【Vue】Composition API 钩子
  • vim、watch、cp和mv
  • df.replace({‘b‘: r‘\s*(\.)\s*‘}, {‘b‘: r‘\1ty‘}, regex=True)