@Autowired 注入转换为构造器注入,导致的构造器代码臃肿,除了 Lombok 外还有别的解决方案吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
vate32
V2EX    Java

@Autowired 注入转换为构造器注入,导致的构造器代码臃肿,除了 Lombok 外还有别的解决方案吗?

  •  
  •   vate32 2020-10-10 11:30:45 +08:00 6217 次点击
    这是一个创建于 1833 天前的主题,其中的信息可能已经有所发展或是发生改变。
    各博客文章说的都是要么使用 Lombok 的 @ RequiredArgsConstructor 注解,要么“考虑这个类是符合足单一职责原则了,将这个类拆分为多个类”。可是对于前者,项目不一定使用 Lombok,对于后者,实际业务情况可能使用很多个依赖类,拆分不太现实。请问还有别的优雅的解决方案吗?
    28 条回复    2023-01-14 12:21:39 +08:00
    NULL2020
        1
    NULL2020  
       2020-10-10 13:10:05 +08:00
    为什么要换,@Autowired 不香吗?
    clf
        2
    clf  
       2020-10-10 13:30:47 +08:00
    @NULL2020 构造器注入也是 @Autowired
    vate32
        3
    vate32  
    OP
       2020-10-10 14:03:23 +08:00   4
    @NULL2020 使用 Autowired 进行注入有空指针风险(例如在构造函数里使用了注入的对象,但是构造函数的调用优先于自动注入,此时调用就会抛出空指针错误),也不方便进行测试,Spring 官方也不推荐使用( Spring Team recommends "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".)。话说平常 IDE 的警告你们都不看的吗
    vantis
        4
    vantis  
       2020-10-10 14:11:39 +08:00
    心情好就去改改 如果是别人代码我就不动
    (程序员怎么回去看 WARNING 233)
    NULL2020
        5
    NULL2020  
       2020-10-10 14:17:29 +08:00
    规则是死的,人是活的,怎么顺手怎么来
    intmax2147483647
        6
    intmax2147483647  
       2020-10-10 14:19:21 +08:00
    @NULL2020 顺手写一个 BUG
    gdtdpt
        7
    gdtdpt  
       2020-10-10 14:21:28 +08:00   1
    看场景吧,也不是说一定不能用非构造器注入的方式,如果你确实需要在一个 bean 的构造函数中做些什么,才需要把相关的 bean 以构造器注入的方式注入到当前实例。
    如果不想这样,那也可以注入 ApplicationContext,具体需要的 Bean 可以从 ApplicationContext 中获取,但是这样做也有可能获取的 Bean 为 null 。
    所以我觉得如果没遇到注入的 Bean 为 null 的情况下,setter 注入,field 注入还是 constructor 注入三种方式不必太纠结,当真正遇到了问题再去分析 bean 的 生成顺序和代码的执行顺序比较好。
    Jooooooooo
        8
    Jooooooooo  
       2020-10-10 14:22:04 +08:00
    臃肿的缺点是?
    hpashencedany1
        9
    hpashencedany1  
       2020-10-10 14:27:26 +08:00
    拆吧, 我在慢慢拆
    sheng3233386
        10
    sheng3233386  
       2020-10-10 14:49:39 +08:00
    我们都用 @Resource
    Resource
        11
    Resource  
       2020-10-10 14:55:03 +08:00   3
    @sheng3233386 #10 谢邀
    Boyce
        12
    Boyce  
       2020-10-10 15:23:35 +08:00
    @Resource 哈哈哈哈
    chendy
        13
    chendy  
       2020-10-10 15:32:20 +08:00
    感觉这个注入就是配合 lombok 最舒服
    不过确实有些场景不能用,比如 RestTemplateBuilder 这种
    不过反正可以自动生成自动补全
    如果一个 bean 要注入的 bean 太多了,考虑重构一下吧
    xiangyuecn
        14
    xiangyuecn  
       2020-10-10 15:33:36 +08:00
    @Resource 这个注解确实牛逼
    MatthewHan
        15
    MatthewHan  
       2020-10-10 15:48:42 +08:00
    @NULL2020 #1 Autowired 都要被淘汰了
    vate32
        16
    vate32  
    OP
       2020-10-10 16:10:21 +08:00
    @Jooooooooo 臭长臭长的,构造函数参数列表很长,不好维护(个人观点)。

    @sheng3233386 直接使用名称的吗,但是这个能够避免上面说的空指针错误吗,好像跟直接使用 autowired 是一样的。

    @chendy 写着着实很爽,但是担心有的地方不让用 Lombok (似乎想多了)

    @gdtdpt 多谢大佬指点,还是得看实际情况来。从 ApplicationContext 获取到 Bean 的方法还没用到过,去学习一下。
    yuhaoyang222
        17
    yuhaoyang222  
       2020-10-10 16:49:51 +08:00
    建造者模式
    STRRL
        18
    STRRL  
       2020-10-10 16:50:03 +08:00
    不清楚 lz 这个问题是在刚刚想做还是已经做一段时间了,不知道有没有遇到过循环依赖的问题。

    constructor 注入需要你先有一个 constructor, 所以手写一个也好 lombok 生成一个也好,还是 IDEA command+N generate 一个也好,都是不错的选择。

    我 jio 得循环依赖才是无法使用 constructor 注入的罪魁祸首,毕竟即使你的 constructor 需要的参数再多,也就是一个注解或者一个快捷键自动生成的事。由于设计上的失误导致的循环依赖会使你压根用不了构造器注入,而且有循环依赖的项目多多少少会有其他的 badsmell ...(破窗。。。
    linvaux
        19
    linvaux  
       2020-10-10 16:57:41 +08:00 via iPhone
    公司禁止使用 lombok,而且,这玩意儿代码能有多冗余?只是自己强迫症发作了吧
    Aresxue
        20
    Aresxue  
       2020-10-10 17:13:45 +08:00
    一般无非就还是插件, idea 官方能出个功能是最好的,虽然构造器更好但如果没有其他配合还是用 field 注入吧,至少不用在新加服务后还要改构造器
    wallfacers
        21
    wallfacers  
       2020-10-10 17:29:35 +08:00
    @lychs1998 构造器注入不是 @Autowired,两者实现区别很大。 @Autowired 是通过 AutowiredAnnotationBeanPostProcessor 进行注入的,而构造器注入是在 Bean 的创建阶段,就会去找到最匹配的构造器,并且准备好构造器需要依赖的 Bean
    ic2y
        22
    ic2y  
       2020-10-10 17:43:31 +08:00   2
    @vate32 Autowired 注入在多人大型项目里,我碰到过一些问题,因为团队成员的理解不一样:容易造成滥用(可能是为了复用某个能力,就注入一堆 bean )、循环依赖(底层模型注入了高层模型的 bean,可能交叉)、多模块的项目很难管理(有种拔出萝卜带出泥的感觉,因为 A 和 B 项目共享了模块 C,B 项目在 C 模块增加了一个 Autowired 注入,A 项目没有感知)。

    我自己认为,构造器注入更好,Spring 官方也推荐,构造器注入在一定程度上:强迫开发者去思考,当前的 bean 为什么要注入其他的依赖。

    如果你用了 Lombok 自动实现了构造器注入,那么这种强迫开发者去思考的动机就没有了,还不如直接 Autowired 。

    手动的用构造器注入(除了某些特定的类,例如 Controller 之类的),我认为有如下优点:
    1.强迫我自己思考:这个注入是否是必须的,是否可以用工具类?用设计模式?或者其他的优雅方法来实现这个逻辑设计。
    2.注入的改变是可感知的。在大型多模块架构的协作工程里,可能很有用。大家在协作里复用了模块 C,一旦你在模块里增加了注入参数,那么其他人用到了模块 C 注入 bean,会立刻编译错误。
    3.因为大型工程里,一般会把某个模块作为一个 jar 包,让其他应用引用,Configuration 里动态声明 Bean 的时候,感觉更从容。因为我知道当前的 bean 所有的依赖都是构造方式注入,我可以从容选择一组自己指定的 bean 进去组装。
    4.某种意义上,实现了业务代码和 Spring 框架的解耦。因为构造器注入的话,就像在写普通的 java 的 pojo 。我们不需要 @Autowired 不需要 @Service 和 @Component,业务类里基本不会 import spring 的东西,依赖 Configuration 的动态装配能力,从构造注入声明了一个个的 bean,完全可控(适合有洁癖的人)。如果有场景,需要移植的话,会很容易,例如:从 Spring 框架移植到 google 的 guice 框架。

    那么,如果构造器注入的 bean 很多的时候,也是一个强迫性的提醒:是实时思考当前的 bean 的设计问题了。
    wysnylc
        23
    wysnylc  
       2020-10-10 18:32:55 +08:00
    构造器无法解决循环依赖问题,spring 推荐构造器注入同时也说了该问题
    没能力解决这个问题的就别瞎折腾
    EminemW
        24
    EminemW  
       2020-10-10 22:48:55 +08:00
    不可以实现 InitializingBean 接口嘛
    br00k
        25
    br00k  
       2020-10-11 01:54:54 +08:00 via iPhone
    推荐构造方法注入。IDE 可以根据属性自动生成构造方法。
    因为构造方法注入默认是不能循环引用,循环引用更多是代码结构或设计不合理,这样能约束你的代码,逼迫你去思考避免循环引用,这是非常好的。
    至于说非要循环引用,请在构造参数上使用 @Lazy 就可以了。这个是不建议的,如果都这样写,还不如用 autowired 。
    我的习惯是只有在 Bean 自己注入自己才会用 @Lazy,这样是避免使用 this 调用内部方法 AOP 失效。
    1194129822
        26
    1194129822  
       2020-10-11 09:33:35 +08:00
    现在大多数项目还是 Filed 注入,spring3 推荐 setter 注入,4 推荐构造器注入,且 4.3 后如果 bean 中有构造器,则不需要 @Autowired, 就已经使用构造器注入,复杂的是 spring 构造器,setter,Filed 注入可以一起工作,所以你使用 Lombok,只要用了 AllArgsContructor/RequiredArgsConstructor,就不需要其他 spring 注解。而且构造器注入无法解决循环依赖,而且是生成的构造器,你也无法操作,所以 @Lazy 解决循环依赖不可用. 但是依然可以在需要循环依赖的 Bean 上使用 @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)提前暴露代理 Bean,不过 spring 官方推荐构造器注入的原因就是程序员自己解决循环依赖
    sheng3233386
        27
    sheng3233386  
       2020-10-12 16:44:13 +08:00
    @vate32 避免不了空指针,在构造函数的调用逻辑建议在 PostConstruct 注解的方法里执行。Resource 没有你说的 warning,哈哈
    Xhack
        28
    Xhack  
       2023-01-14 12:21:39 +08:00
    @ic2y 需要注入的类 比如 xxService 也不需要 @Service 注解吗 ???????
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2739 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 00:18 PVG 08:18 LAX 17:18 JFK 20:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86