Spring6 从@Autowired属性注入 出现警告提示说起

Spring升级到6后(原先用的3),@Autowired注解 出现警告提示,看着真是膈应~~~~

警告提示:

Field injection is not recommended, 

意思是: 不推荐使用属性注入

建议意见:

Reports injected or autowired fields in Spring components.

The quick-fix suggests the recommended constructor-based dependency injection in beans and assertions for mandatory fields.

意思是:Spring 团队建议: 始终在您的 bean 中使用基于构造函数的依赖注入。

查了下资料,原来从spring4.0 开始,官方就不推荐@Autowire的使用在字段上。

在 Spring 3.x 的时候 Spring 推荐 Setter 方法注入,第二段表示:一些纯粹主义者喜欢基于构造函数的注入。提供所有对象依赖项意味着对象总是在完全初始化状态下返回给客户机(调用)代码。缺点是对象不太容易重新配置和重新注入。

Spring 3.x Constructor-based or setter-based DI?

The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy, especially when properties are optional. Setter methods also make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is a compelling use case.Some purists favor constructor-based injection. Supplying all object dependencies means that the object is always returned to client (calling) code in a totally initialized state. The disadvantage is that the object becomes less amenable to reconfiguration and re-injection.

在 Spring 4.x 的时候 Spring 推荐构造器注入,第二段表示:Setter 注入应该主要用于可选的依赖项,这些依赖项可以在类中分配合理的默认值。否则,必须在代码使用依赖项的任何地方执行非空检查。setter 注入的一个好处是,setter 方法使该类的对象能够在以后重新配置或重新注入。

Spring 4.x Constructor-based or setter-based DI?

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.

解决

如果一定要使用属性注入, 可以使用 @Resource 代替 @Autowired 注解

@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。

如果我们想使用按照名称byName来装配,可以结合@Qualifier注解一起使用。

这里就需要了解下 @Resource 和 @Autowired的区别:

1.提供方不同

@Autowired 是Spring提供的,@Resource 是J2EE提供的。

2.装配时默认类型不同

@Autowired只按type装配,@Resource默认是按name装配。

3、使用区别

(1)@Autowired与@Resource都可以用来装配bean,都可以写在字段或setter方法上

(2)@Autowired默认按类型装配,默认情况下必须要求依赖对象存在,如果要允许null值,可以设置它的required属性为false。如果想使用名称装配可以结合@Qualifier注解进行使用。

(3)@Resource,默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行名称查找。如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

@Resource有两个重要的属性:name和type

spring有三种注入方式:

1. Constructor-based dependency injection 基于构造器注入

@Controllerpublic class AaController {    private final AaService aaService;    private final BbService bbService;        @Autowired    public AaController(AaService aaService, BbService bbService) {        this.aaService = aaService;        this.bbService = bbService;    }}

2. Setter-based dependency injection 基于set方法注入

@Controllerpublic class AaController {    private AaService aaService;    private BbService bbService;        @Autowired    public void setAaService(AaService aaService) {        this.aaService = aaService;    }    @Autowired    public void setBbService(BbService bbService) {        this.bbService = bbService;    }}

3. Field-based dependency injection 基于属性字段注入

@Controllerpublic class  AaController {    @Autowired    private AaService aaService;    @Autowired    private BbService bbService;}

从具体实现来看,基于属性字段的最为简洁,既避免了添加繁冗的setter样板代码,并且无需为类声明构造函数,既然 Spring自己都不推荐基于字段注入 ,那必然有其弊端,只是为了兼容性才继续支持的(猜测)。


基于字段注入, 是 ByType 注入,有以下弊端:

1. 基于属性注入的方式, 违背单一职责原则

因为现在的业务一般都会使用很多依赖, 但拥有太多的依赖通常意味着承担更多的责任,而这显然违背了单一职责原则.

并且类和依赖容器强耦合,不能在容器外使用。

2. 基于属性注入的方式, 容易导致Spring 初始化失败

因为现在在Spring特别是Spring Boot使用中, 经常会因为初始化的时候, 由于属性在被注入前就引用而导致npe(空指针错误),

进而导致容器初始化失败(类似下面代码块). Java 在初始化一个类时,

是按照 静态变量或静态语句块 –> 实例变量或初始化语句块 –> 构造方法 -> @Autowired 的顺序。

所以在执行这个类的构造方法时,person 对象尚未被注入,它的值还是 null。

3. 通过@Autowired 注入, 又因为是 ByType 注入, 因此有可能会出现两个相同的类型bean

如下代码快, 就会产生两个相同的Bean, 进而导致Spring 装配失败

spring推荐使用构造器注入,但是构造器注入太繁琐。

而lombok提供的注解@RequiredArgsConstructor,用于依赖注入,在使用@RequiredArgsConstructor之后需要注意,参数类型必须要是final的

private final 类型 参数名;

相当于实现了构造器注入,而省却了最繁琐的构造器部分,使代码实现更为简洁

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值