V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tinotino654321
V2EX  ›  Java

Spring 依赖注入最佳实践?

  •  
  •   tinotino654321 · 2022-02-21 19:56:52 +08:00 · 5159 次点击
    这是一个创建于 767 天前的主题,其中的信息可能已经有所发展或是发生改变。
    Spring 官方文档里推荐的是用 Constructor 注入,可选依赖用 Setter 注入。
    但是实际在项目里一般用哪种注入呢?
    我工作没多久,见到的大部分都是用 Field 注入。
    50 条回复    2022-02-23 10:52:08 +08:00
    chendy
        1
    chendy  
       2022-02-21 20:04:28 +08:00
    final 字段 + 构造方法注入 + lombok 的 RequireArgsConstructor 注解
    是不是最佳不知道,应该是字最少的
    但是不能用来处理 RestTemplateBuilder 这样的特殊 bean
    issakchill
        2
    issakchill  
       2022-02-21 20:13:19 +08:00
    我也是用 1 楼的方法
    有个难处理的地方是这个类的子类要手写构造方法,不知道有没有更方便的做法?
    sutra
        3
    sutra  
       2022-02-21 20:24:56 +08:00
    Constractor 注入的话,可以把 field 标记为 final ,其它的则不行。
    sutra
        4
    sutra  
       2022-02-21 20:30:19 +08:00   ❤️ 1
    fpure
        5
    fpure  
       2022-02-21 20:41:41 +08:00   ❤️ 15
    我不管,我就要用 @Autowire 属性注入
    Bingchunmoli
        6
    Bingchunmoli  
       2022-02-21 20:52:04 +08:00
    官方推荐使用构造器,而旧项目和旧 Spring 用的比较多的是 autowired 和 resource , 都行,其实按推荐确实好点
    7911364440
        7
    7911364440  
       2022-02-21 20:54:11 +08:00
    Constractor+1
    Oktfolio
        8
    Oktfolio  
       2022-02-21 20:55:07 +08:00
    我是 Constractor + Setter
    Oktfolio
        9
    Oktfolio  
       2022-02-21 20:55:26 +08:00
    @Oktfolio 啊这,复制了楼上的 typo
    giiiiiithub
        10
    giiiiiithub  
       2022-02-21 21:19:24 +08:00
    如果依赖是创建对象时必须的,肯定是构造器注入。否则应该用 setter 注入,最次是 field 。

    以上是基于:1. 依赖是否必须在构造对象时提供,2. 方便 mock

    但实际使用使用是另一回事。用 spring 那一套,即便用 filed 注入一般也没什么问题
    tinotino654321
        11
    tinotino654321  
    OP
       2022-02-21 21:35:26 +08:00
    @sutra 实际上很少有依赖注入后会被修改的情况吧? final 其实也不是很重要?
    sutra
        12
    sutra  
       2022-02-21 21:41:30 +08:00
    @tinotino654321 final 的目的是为了防止被修改,也可以从语义角度表示,不可以修改。
    sutra
        13
    sutra  
       2022-02-21 21:42:09 +08:00
    @Oktfolio 我发完就发现我的 typo 了,然而 V2EX 不能改。哈哈哈……
    tinotino654321
        14
    tinotino654321  
    OP
       2022-02-21 21:42:12 +08:00
    @giiiiiithub 我觉得 Field 注入最方便,但既是优点也是缺点。
    优点是可以循环依赖,而且加依赖方便,不用改 Constructor 。
    缺点是 Class 容易循环依赖,责任不清晰,并且依赖很多,容易形成屎山。
    Mock 的话 Mockito 也可以 InjectMocks ,问题不是很大。
    sutra
        15
    sutra  
       2022-02-21 21:48:01 +08:00 via iPhone
    constructor 注入也能循环依赖,加 lazy 注解。
    giiiiiithub
        16
    giiiiiithub  
       2022-02-21 22:02:08 +08:00
    @tinotino654321 跟依赖循环没多大关系。主要是依赖应该不应该放在构造函数?能不能被 mock ? 你可以想象如果提供给外部使用,就需要问自己两个问题:1. 什么是必须的什么是可选的? 2. 什么是可以被修改的什么是不能被修改的?
    liuxu
        17
    liuxu  
       2022-02-21 22:15:08 +08:00
    新版的 idea 不是推荐 contractor 里面用 @autowired 注入么
    WispZhan
        18
    WispZhan  
       2022-02-21 22:59:42 +08:00 via Android
    必然是按官方来,不然提 PR 都过不了 bot
    honamx
        19
    honamx  
       2022-02-21 23:23:06 +08:00
    @RequiredArgsConstructor + private final
    appstore54321
        20
    appstore54321  
       2022-02-21 23:35:41 +08:00 via Android
    构造函数注入,写单元测试时就知道了,这样最方便 mock 。直接 autowired 一个成员这怎么测。
    NotFoundEgg
        21
    NotFoundEgg  
       2022-02-21 23:51:35 +08:00
    我一般用构造器注入
    用 Autowired 注入 idea 会有警告,看着难受
    leeg810312
        22
    leeg810312  
       2022-02-21 23:52:51 +08:00 via Android
    顺便问下,service 接口实现按推荐的构造函数注入依赖,那么单元测试 mockito 怎么写比较好
    Kontinue
        23
    Kontinue  
       2022-02-22 08:25:37 +08:00
    @NotFoundEgg 同,idea 推荐哪种方式用哪种哈哈哈,不然全是波浪线和 warning 很难受。人家既然给出提示肯定是有他的必要性的
    thetbw
        24
    thetbw  
       2022-02-22 09:11:17 +08:00
    @appstore54321 我们从没写过单元测试😅
    chendy
        25
    chendy  
       2022-02-22 09:19:41 +08:00
    @leeg810312 直接 @ Mock 定义 mock 依赖,然后自己把 service new 出来
    hingbong
        26
    hingbong  
       2022-02-22 09:24:28 +08:00
    kotlin 表示一般用 constructor, 偶尔是 setter
    gitdoit
        27
    gitdoit  
       2022-02-22 09:25:33 +08:00   ❤️ 2
    idea 治好了我用 @Autowired 的毛病
    sheeta
        28
    sheeta  
       2022-02-22 09:26:15 +08:00
    @Kontinue @Resource 注入就没有警告了,哈哈
    summerLast
        29
    summerLast  
       2022-02-22 09:56:18 +08:00
    同一楼 final 字段 + 构造方法注入 + lombok 的 RequireArgsConstructor 注解
    补 需要 注入值的 或 特殊的 不用 final 修饰 自己手动加对应注解
    qaqLjj
        30
    qaqLjj  
       2022-02-22 09:57:08 +08:00
    @sutra 这篇文章讲了 constructor 注入可以防止空指针,但是我试了 `@AutoWired/@Resource` 注解,用这两个注解时,缺依赖的话 springboot 都启动不起来,所以不管是构造器注入还是字段注入都不会造成空指针啊
    wolfie
        31
    wolfie  
       2022-02-22 09:58:41 +08:00
    @qaqLjj #30
    构造器注入,没有合格的 bean 一样没法创建。
    hambers
        32
    hambers  
       2022-02-22 10:14:25 +08:00
    构造器注入 如果以来的注入对象很多的话,构造方法不是参数很多的样子。 强迫症看着有点不舒服,有啥好办法么
    Edsie
        33
    Edsie  
       2022-02-22 10:29:11 +08:00
    推荐构造器注入,但实际用的时候常用 @AutoWired
    banmuyutian
        34
    banmuyutian  
       2022-02-22 11:40:04 +08:00
    @hambers #32
    lombok 注解
    xuanbg
        35
    xuanbg  
       2022-02-22 11:47:33 +08:00
    field 注入最简单,但安全性不太好。我都是用构造器注入,这样不会飘红,强迫症你们不用学。
    xuanbg
        36
    xuanbg  
       2022-02-22 11:48:39 +08:00
    @hambers 注入对象很多的话,你要反思自己的代码结构是否合理了。
    NotFoundEgg
        37
    NotFoundEgg  
       2022-02-22 11:54:44 +08:00
    @hambers
    Lombok 的 RequireArgsConstructor 注解可以解决这个问题,但从设计上来说一个类注入了过多的对象,可能违背了单一职责原则(虽然实际上来说这种情况确实特别常见🤣)
    wolfie
        38
    wolfie  
       2022-02-22 12:02:37 +08:00
    @appstore54321 #20
    单元测试时候 脱离 spring ?
    dcsuibian
        39
    dcsuibian  
       2022-02-22 12:04:38 +08:00
    Constractor ,因为 idea 不会有波浪线。(测试的那里不会有)
    循环依赖用 settter
    chendy
        40
    chendy  
       2022-02-22 12:15:24 +08:00
    @wolfie 依赖全 mock ,直接脱离 spring 单独跑
    spring 的测试工具其实更多是集成测试不是单元测试(带数据库和接口之类的)
    cheng6563
        41
    cheng6563  
       2022-02-22 14:19:36 +08:00
    构造器注入的话 如果循环依赖会炸掉
    shanghai1943
        42
    shanghai1943  
       2022-02-22 14:21:00 +08:00
    构造器注入的话,万一是需要注入很多 bean 咋整。。不得写一长串么
    zzfer
        43
    zzfer  
       2022-02-22 16:41:21 +08:00
    @shanghai1943 我们使用的 lombok 的 RequireArgsConstructor 注解
    shanghai1943
        44
    shanghai1943  
       2022-02-22 16:46:24 +08:00
    @zzfer 👍学习了。
    incubus
        45
    incubus  
       2022-02-22 17:23:23 +08:00
    @fpure 为啥不用 @Resource
    zhady009
        46
    zhady009  
       2022-02-22 17:28:41 +08:00
    用构造器就行了 写多了就明白为什么 也能一定程度上把控代码质量
    hambers
        47
    hambers  
       2022-02-22 17:52:55 +08:00
    @banmuyutian 如果 有几个待注入的 field 有循环以来需要 lazy 一下 咋整呢? 能在 final field 上加 @lazy
    Loku
        48
    Loku  
       2022-02-22 18:04:27 +08:00
    Constructor 注入
    NeoZephyr
        49
    NeoZephyr  
       2022-02-23 10:44:18 +08:00
    不知道为啥不推荐 field 注入。如果全部用构造器注入的话,会遇到循环依赖的
    deweixu
        50
    deweixu  
       2022-02-23 10:52:08 +08:00
    我以前用 @AutoWired ,但是 idea 会给我警告,现在改用 setter 了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2932 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 14:10 · PVG 22:10 · LAX 07:10 · JFK 10:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.