为什么Spring和IDEA都不推荐使用 @Autowired 注解

目录
  • 前言
  • Spring为什么不推荐使用@Autowired 注解
    • 背景
    • 原因
    • 解决
  • 思考
  • @Autowired, @Qualifier, @Resource, 三者有何区别
  • 参考文档

前言

请看下面几个问题

  • Spring为什么不推荐使用@Autowired 注解?
  • 为什么推荐使用@Resource 代替 @Autowired 注解?
  • 如何快速使用构造注入代替 @Autowired ?
  • @Autowired, @Qualifier, @Resource, 三者有何区别?

下面, 我们带着以上问题去梳理和学习, 体会知识之间的关联性

Spring为什么不推荐使用@Autowired 注解

背景

做开发的同学可能都会发现, idea 在我们经常使用的@Autowired 注解上添加了警告
警告内容是: Field injection is not recommended, 译为: 不推荐使用属性注入

我们点击右侧三个小点查看描述, 可以看到信息如下图

原因详情描述: Inspection info: Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".
译为: Spring 团队建议: 始终在您的 bean 中使用基于构造函数的依赖注入。始终对强制依赖项使用断言

原因

为什么 Spring 建议我们在Bean中使用构造注入呢?
想要回答这个问题, 我们需要了解 Spring的依赖注入(DI)方式
Spring常用的注入方式有: 简单类型注入, 集合类型注入, 域属性自动注入, 自动注入的类别, 空值注入, 构造注入
可以简化为: 属性注入, 构造方法注入, set 方法注入

下面, 来用代码展示下三种方式注入

属性注入
可以看到, 我们开发最常用的就是属性注入

@RestController
public class AppointmentNumberConfigurationController {

    @Autowired
    private AppointmentNumberConfigurationService numberConfigurationService;
}

set 方法注入
set 方法注入也会用到@Autowired注解,但使用方式与属性注入有所不同,
属性注入是用在成员变量上,而set 方法的时候,是用在成员变量的Setter函数上。

@RestController
public class AppointmentNumberConfigurationController {

    private AppointmentNumberConfigurationService numberConfigurationService;

    @Autowired
    public void setNumberConfigurationService(AppointmentNumberConfigurationService numberConfigurationService) {
        this.numberConfigurationService = numberConfigurationService;
}

构造方法注入
Constructor Injection是构造器注入,是我们最为推荐的一种使用方式。
但是, 每次注入都按照这样的流程去构造注入的话, 会显得比较麻烦.
至于如何去简化这一步骤, 我们可以继续往下看.

@RestController
public class AppointmentNumberConfigurationController {

    final AppointmentNumberConfigurationService numberConfigurationService;

    public AppointmentNumberConfigurationController(AppointmentNumberConfigurationService numberConfigurationService) {
        this.numberConfigurationService = numberConfigurationService;
    }
    }

三种方式对比如下

使用属性注入可能会出现的问题

基于属性注入的方式, 违背单一职责原则
因为现在的业务一般都会使用很多依赖, 但拥有太多的依赖通常意味着承担更多的责任,而这显然违背了单一职责原则.
并且类和依赖容器强耦合,不能在容器外使用。

基于属性注入的方式, 容易导致Spring 初始化失败
因为现在在Spring特别是Spring Boot使用中, 经常会因为初始化的时候, 由于属性在被注入前就引用而导致npe(空指针错误),
进而导致容器初始化失败(类似下面代码块). Java 在初始化一个类时,
是按照 静态变量或静态语句块 –> 实例变量或初始化语句块 –> 构造方法 -> @Autowired 的顺序。
所以在执行这个类的构造方法时,person 对象尚未被注入,它的值还是 null。

通过@Autowired 注入, 又因为是 ByType 注入, 因此有可能会出现两个相同的类型bean
如下代码快, 就会产生两个相同的Bean, 进而导致Spring 装配失败

//2. 基于属性注入的方式, 容易导致Spring 初始化失败
@Autowired
private Person person;

private String company;

public UserServiceImpl(){
    this.company = person.getCompany();
}

//3. 通过@Autowired 注入, 又因为是 ByType 注入, 因此有可能会出现两个相同的类型bean
public interface IUser {
    void say();
}

@Service
public class User1 implements IUser{
    @Override
    public void say() {
    }
}

@Service
public class User2 implements IUser{
    @Override
    public void say() {
    }
}

@Service
public class UserService {

    @Autowired
    private IUser user;
}

解决

如果一定要使用属性注入, 可以使用 @Resource 代替 @Autowired 注解
@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。
如果我们想使用按照名称byName来装配,可以结合@Qualifier注解一起使用。

如果可能的话, 尽量使用构造注入
Lombok提供了一个注解@RequiredArgsConstructor, 可以方便我们快速进行构造注入, 例如:

@RestController
@RequiredArgsConstructor
public class AppointmentNumberConfigurationController {

    final AppointmentNumberConfigurationService numberConfigurationService;
    }

同时需要注意:

使用@RequiredArgsConstructor注解需要导入Lombok 包 或者安装lombok 插件

  <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.16</version>
  </dependency>

必须声明的变量为final

根据构造器注入的,相当于当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,
其中每个参数代表一个对其他类的依赖。基于构造方法为属性赋值,容器通过调用类的构造方法将其进行依赖注入

思考

为什么推荐使用@Resource,不推荐使用@Autowired

通过对问题1 的梳理, 我们可以知道.
因为@Autowired 注解在Bean 注入的时候是基于ByType, 因此会由于注入两个相同类型的Bean导致装配失败

@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。
如果我们想使用按照名称byName来装配,可以结合@Qualifier注解一起使用。

@Resource装配顺序:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

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

@Autowired, @Qualifier, @Resource, 三者有何区别

  • @Autowired: 通过byType 方式进行装配, 找不到或是找到多个,都会抛出异常。
  • @Qualifier: 如果想让@Autowired 注入的Bean进行 byName装配, 可以使用 @Qualifier 进行指定
  • @Resource :作用相当于@Autowired,只不过 @Resource 默认按照byName方式装配, 如果没有匹配, 则退回到 byType 方式进行装配

参考文档

为什么IDEA不推荐你使用@Autowired?

@Autowired和@Resource的区别是什么?

到此这篇关于为什么Spring和IDEA都不推荐使用 @Autowired 注解的文章就介绍到这了,更多相关Spring IDEA @Autowired 注解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring为什么不推荐使用@Autowired注解详析

    目录 引言 Spring的三种注入方式 属性(filed)注入 构造器注入 set方法注入 属性注入可能出现的问题 问题一 问题二 问题三 spring建议 使用@Resource代替@Autowired 使用@RequiredArgsConstructor构造器方式注入 总结 引言 使用IDEA开发时,同组小伙伴都喜欢用@Autowired注入,代码一片warning,看着很不舒服,@Autowired作为Spring的亲儿子,为啥在IDEA中提示了一个警告:Field injection i

  • SpringBoot @Autowired注解注入规则介绍

    目录 @Autowired注解注入规则 验证 小结一下 @Autowired注解无法自动注入的错误 @Autowired注解注入规则 @Autowired - 注入默认根据类型,匹配不到则根据bean名字 Spring中注解方式的默认beanName生成规则: 在Spring中,当我们配置一个bean的时候,可以不指定name,这样的话,Spring会生成一个默认的beanName 1. 驼峰形式类名首字母小写:UserService--userService 2. 特殊情况--当类名的首字母和

  • idea中@Autowired注解下变量报红的解决

    目录 idea中@Autowired注解下变量报红 问题 解决方法 注解@Autowired--警告(亲测可用) 变量(filed)注入 构造器注入 set方法注入 小结下 idea中@Autowired注解下变量报红 问题 idea中@Autowired注解下变量报红 这个不是错误,只是一个警告而已,其实不解决也是可以启动项目的 解决方法 1.修改设置 file–>settings–>Inspections–>spring Core–>Code–>Autowiring fo

  • @Autowired注解注入的xxxMapper报错问题及解决

    目录 @Autowired注解注入的xxxMapper报错 项目场景 问题描述 解决方案 分析 @Autowired无法加载Mapper,报错404或者500 @Autowired注解注入的xxxMapper报错 项目场景 Mybatis-Plus测试 问题描述 在Mybatis-Plus场景的测试中发现,通过@Autowired注解注入的userMapper会报错 这是因为UserMapper 并不是一个可以创建出对象的一个类,而是一个接口. @Override public void run

  • @Autowired注解在抽象类中失效的原因及解决

    @Autowired注解在抽象类中失效 最近在工作中遇到这个问题,在抽象类中使用Autowired这个注解,注入mybatis的dao时,总是出现空指针异常,通过日志的打印,发现是这个dao注入失败为空.然后通过new出spring上下文对象,再去调用getBean()方法,获取到这个注入的dao,这样是可行的,但是总是觉得这不是最佳实践,一定有比这个更加优雅的方式能解决这个问题. 我们来还原一下这个问题: 1.定义一个抽象类 声明为spring组件,在其中自动装配另一个bean: @Compo

  • 关于@Autowired注解和静态方法及new的关系

    目录 @Autowired注解和静态方法及new关系 一.@autowired 与new 二.@autowired 与静态方法 1.spring框架应用中有些静态方法需要依赖被容器管理的类 2.原理剖析 3.解决办法 @Autowired和new对象有什么区别 如下例子所示 小结 @Autowired注解和静态方法及new关系 一.@autowired 与new new出来的对象无法调用@Autowired注入的Spring Bean,否则报空指针异常, @Autowired注入Spring B

  • Spring注解@Autowired背后实现的原理

    目录 前言 使用spring开发时,进行配置主要有两种方式,一是xml的方式,二是java config的方式. spring技术自身也在不断的发展和改变,从当前springboot的火热程度来看,java config的应用是越来越广泛了,在使用java config的过程当中,我们不可避免的会有各种各样的注解打交道,其中,我们使用最多的注解应该就是@Autowired注解了.这个注解的功能就是为我们注入一个定义好的bean. 那么,这个注解除了我们常用的属性注入方式之外还有哪些使用方式呢?它

  • 为什么Spring和IDEA都不推荐使用 @Autowired 注解

    目录 前言 Spring为什么不推荐使用@Autowired 注解 背景 原因 解决 思考 @Autowired, @Qualifier, @Resource, 三者有何区别 参考文档 前言 请看下面几个问题 Spring为什么不推荐使用@Autowired 注解? 为什么推荐使用@Resource 代替 @Autowired 注解? 如何快速使用构造注入代替 @Autowired ? @Autowired, @Qualifier, @Resource, 三者有何区别? 下面, 我们带着以上问题

  • 详谈Spring对IOC的理解(推荐篇)

    一.IOC控制反转和DI依赖注入 1.控制反转,字面可以理解为:主动权的转移,原来一个应用程序内的对象是类通过new去主动创建并实例化的,对对像创建的主动权在程序代码中.程序不仅要管理业务逻辑也要管理对的象创建和依赖关系.这是很累的,也跟软件工程 "低耦合高内聚" 的概念不十分符合. 有了spring的ioc容器之后,对象的实例化和依赖关系管理都由IOC容器进行统一管理,主体类只要依赖ioc容器就够了,需要啥,容器会给他注入进去,也就是只要声明对象不用再主动去new,ioc容器帮忙把相

  • Eclipse搭建spring开发环境图文教程(推荐)

    1 安装 springsource-tool-suite: (1)在官网上找安装Eclipse的对应版本(我的Eclipse版本是4.5.1,对应版本是3.7.2) http://download.springsource.com/release/TOOLS/update/3.7.2.RELEASE/e4.5/springsource-tool-suite-3.7.2.RELEASE-e4.5.1-updatesite.zip (2)INSTALL NEW SOFTWARE (3)下载sprin

  • 彻底搞明白Spring中的自动装配和Autowired注解的使用

    一.自动装配 当Spring装配Bean属性时,有时候非常明确,就是需要将某个Bean的引用装配给指定属性.比如,如果我们的应用上下文中只有一个org.mybatis.spring.SqlSessionFactoryBean类型的Bean,那么任意一个依赖SqlSessionFactoryBean的其他Bean就是需要这个Bean.毕竟这里只有一个SqlSessionFactoryBean的Bean. 为了应对这种明确的装配场景,Spring提供了自动装配(autowiring).与其显式的装配

  • Spring使用@Autowired注解静态实例对象方式

    目录 Spring @Autowired注解静态实例对象 问题 原因 解决方案 方式一 方式二 方式三 方式四 总结 @Autowired注解和静态方法 一.业务场景 二.原理剖析 三.解决方法 1.将@Autowire加到构造方法上 2.用@PostConstruct注解 Spring @Autowired注解静态实例对象 问题 最近项目小组在重新规划工程的业务缓存,其中涉及到部分代码重构,过程中发现有些工具类中的静态方法需要依赖别的对象实例(该实例已配置在xml成Spring bean,非静

  • 解析Idea为什么不推荐使用@Autowired进行Field注入

    目录 Spring常见的DI方式 @Autowired VS @Resource 各种DI方式的优缺点 Field注入的缺点 为什么IDEA只对@Autowired警告 大家在使用IDEA开发的时候有没有注意到过一个提示,在字段上使用Spring的依赖注入注解@Autowired后会出现如下警告 Field injection is not recommended (字段注入是不被推荐的) 但是使用@Resource却不会出现此提示 网上文章大部分都是介绍两者的区别,没有提到为什么,当时想了好久

  • 基于Spring@Autowired注解与自动装配详谈

    1 配置文件的方法 我们编写spring 框架的代码时候.一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量.并且要配套写上 get 和 set方法. Boss 拥有 Office 和 Car 类型的两个属性: 清单 3. Boss.java package com.baobaotao; public class Boss { private Car car; private Office office; // 省略 get/setter @Override p

  • Spring使用@Autowired注解实现自动装配方式

    目录 Spring支持注解配置 引入注解依赖 启用注解 使用@Autowired注解实现自动装配 1.IOC容器配置 2.实体类使用@Autowired注解注入属性 3.测试结果 @Autowired注解的使用和注入规则 1.使用在变量域上面 2.@Autowired注解使用在构造器上面 Spring支持注解配置 引入注解依赖 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="ht

  • Spring详细讲解@Autowired注解

    目录 java注解 spring注解 (1)配置文件形式 (2)注解形式 @Autowired的解析 @Autowired的生效流程 java注解 在解释spring的注解之前,先了解一下什么是java的注解?:Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制. Java中类.变量.参数. 包等都可以添加注解,java的注解可以通过反射来获取到标注的内容,在编译器生成字节码文件时,标注信息也添加进去.当运行时,JVM可以根据标注信息获取相应的信息.

随机推荐