温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2022-04-02 15:49:26 来源:亿速云 阅读:506 作者:iii 栏目:开发技术

今天小编给大家分享一下Spring和IDEA为什么都不推荐使用@Autowired注解的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

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

    背景

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

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

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

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

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

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

    原因

    为什么 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和IDEA为什么都不推荐使用@Autowired注解

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

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

    以上就是“Spring和IDEA为什么都不推荐使用@Autowired注解”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI