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

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

  •  
  •   vate32 · 2020-10-10 11:30:45 +08:00 · 5619 次点击
    这是一个创建于 1497 天前的主题,其中的信息可能已经有所发展或是发生改变。
    各博客文章说的都是要么使用 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   ·   实用小工具   ·   5504 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 08:42 · PVG 16:42 · LAX 00:42 · JFK 03:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.