当前位置: 首页 > 后端技术 > Java

Spring有哪几种依赖注入方式?官方推荐是什么?

时间:2023-04-02 00:02:35 Java

作者:Richard_Yi\来源:juejin.cn/post/6844904056230690824IDEA提示不推荐使用Fieldinjection使用IDEA进行Spring开发时,在字段上使用@Autowired注解时,会发现IDEA会有一个警告提示:不推荐字段注入检查信息:Spring团队建议:“始终在bean中使用基于构造函数的依赖注入。始终对强制依赖使用断言”。翻译过来就是:不推荐使用field-based注入。Spring开发团队建议您始终在SpringBean中使用基于构造函数的依赖注入。始终对所需的依赖项使用断言。例如下面的代码:@ServicepublicclassHelpService{@Autowired@Qualifier("svcB")privateSvcsvc;publicvoidsayHello(){svc.sayHello();}}publicinterfaceSvc{voidsayHello();}@ServicepublicclassSvcBimplementsSvc{@OverridepublicvoidsayHello(){System.out.println("你好,这是服务B");}}把光标放在@Autowired,用Alt+Enter修改,代码会根据Constructor改变Injection方法,修改后:@ServicepublicclassHelpService{privatefinalSvcsvc;@AutowiredpublicHelpService(@Qualifier("svcB")Svcsvc){//Assert.notNull(svc,"svc不能为null");这个.svc=svc;}publicvoidsayHello(){svc.sayHello();}}如果按照Spring团队的建议,如果svc是必要的依赖,应该使用Assert.notNull(svc,"svcmustnotbenull")来确认。这个warning提示很容易修复,但是我觉得更重要的是理解Spring团队为什么会提出这样的建议?直接使用这种基于字段的注入有什么问题呢?首先我们要知道Spring中的依赖注入分为三种方式:基于字段的注入(propertyinjection)基于构造器注入(constructorinjection)的setter-based注入1.基于字段的注入所谓字段基于注入是在bean变量上使用注解进行依赖注入。本质上,它是通过反射直接注入到场中的。这是我平时开发中见得最多,也是最熟悉的方式。同时也是Spring团队不推荐的方式。例如:@AutowiredprivateSvcsvc;2、在setter方法注入的基础上,使用对应变量的setXXX()方法,并在方法上使用注解,完成依赖注入。例如:privateHelperhelper;@AutowiredpublicvoidsetHelper(Helperhelper){this.helper=helper;}注意:在Spring4.3及之后的版本中,setter上的@Autowired注解可以省略。推荐一个SpringBoot基础教程和实例:https://github.com/javastacks...3.基于构造函数注入,将所有需要的依赖放在带注解的构造方法的参数中,在构造方法中完成对应变量的初始化,这种方法是基于构造方法的注入。例如:privatefinalSvcsvc;@AutowiredpublicHelpService(@Qualifier("svcB")svcsvc){this.svc=svc;}在Spring4.3及之后的版本中,如果这个类只有一个构造函数,那么这个构造函数上面也可以不写@Autowired注解.基于字段注入的好处可以看到,这种方法非常简洁,代码看起来也非常简单易懂。您的类可以专注于业务而不会被依赖注入污染。您只需在变量上添加@Autowired,不需要特殊的构造函数或设置器,依赖注入容器将提供您需要的依赖项。基于字段的注入的缺点成功与失败萧何基于字段的注入虽然简单,但是会带来很多问题。这些问题是我平时开发和阅读项目代码时经常遇到的。很容易违反单一职责原则。使用这种基于字段注入的方式,添加依赖非常简单。即使你的类中有十几个依赖项,你可能会觉得没有问题。普通开发者可能会不自觉地给A类添加很多依赖。但是当使用构造函数注入时,在某个时刻,构造函数中的参数变得如此之多,以至于很明显出了问题。依赖太多通常意味着你的类要承担更多的责任,这显然违反了单一责任原则(SRP:Singleresponsibilityprinciple)。这个问题在我们公司的项目代码中确实很常见。依赖注入框架的核心思想之一是容器管理的类不应该依赖于容器使用的依赖项。也就是说,这个类应该是一个简单的POJO(PlainOrdinaryJavaObject),可以单独实例化,你也可以为它提供它需要的依赖。这个问题具体可以表现在:你的类和依赖的容器是强耦合的,你不能在容器外使用你的类。您不能绕过反射(例如,单元测试时)进行实例化。必须通过依赖容器来实例化,更像是一个集成测试,不能使用属性注入构建不可变对象(final修饰变量)Spring开发组的建议既然可以混合constructor-based和setter-basedDI,那么它一个很好的经验法则是对强制依赖项使用构造函数,对可选依赖项使用setter方法或配置方法。简单来说,如果强制依赖是可选的,就使用构造方法,对于变量依赖,使用setter注入。当然,你可以在同一个类中使用这两个方法。构造函数注入更适合针对不可变性的强制注入,setter注入更适合可变性注入。下面看看Spring推荐的原因。第一种是基于构造函数注入。Spring团队普遍提倡构造函数注入,因为它使人们能够将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。此外,构造函数注入的组件总是以完全初始化的状态返回给客户端(调用)代码。作为旁注,大量的构造函数参数是一种糟糕的代码味道,暗示该类可能有太多责任,应该重构以更好地解决关注点的适当分离。Spring团队提倡使用constructor-basedinjection,因为一方面可以将依赖注入到一个不可变的变量中(注:final修饰的变量),另一方面也可以保证取值这些变量不会为空。另外,通过构造方法完成依赖注入的组件(注:如各种服务)可以保证在被调用时完全就绪。同时,从代码质量的角度来看,一个巨大的构造函数通常代表一种代码味道,类可能承担了太多的责任。而对于基于setter的注入,他们是这样说的:Setter注入应该主要只用于可选的依赖项,这些依赖项可以在类内分配合理的默认值。否则,必须在代码使用依赖项的任何地方执行非空检查。setter注入的一个好处是setter方法使该类的对象可以在以后重新配置或重新注入。基于setter的注入应该只用于注入非必需的依赖,并且应该为这种依赖提供一个类合理的默认值。如果使用setter来注入所需的依赖项,将会有太多的空检查淹没代码。使用setter注入的一个优点是这种依赖关系可以很容易地更改或重新注入。总结以上就是本文的全部内容。希望阅读本文后,您对Spring的依赖注入有更深入的了解。近期热点文章推荐:1.1,000+Java面试题及答案(2021最新版)2.别在满屏的if/else中,试试策略模式,真的很好吃!!3.操!Java中xx≠null的新语法是什么?4、SpringBoot2.5发布,深色模式太炸了!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!