Spring依赖注入,为什么不推荐用@Autowired,而是用构造函数注入呢?

向东       2024/05/16       技术       共2151字       900

依赖注入的方式

首先,要搞清楚Spring依赖注入共有哪几种方式:

  • 属性注入
  • Setter注入
  • 构造方法注入

@Autowired和@Resource都属于是属性注入的范畴,下面是一个简单的属性注入示例:


@RestController
public class UserController {
    // 属性对象
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

属性注入有什么优缺点?

优点:简单

缺点如下:

  • 功能性问题:不可注入一个不可变的对象(被注入的对象不能使用final修饰)
  • 通用性问题:只能适用于Ioc容器
  • 设计原则问题:注入实现越简单,那么滥用它的概率也越大,所以出现违背单一职责原则的概率也越大。
  • 使用field注入可能会导致循环依赖,即A里面注入B,B里面又注入A,这种循环依赖的错误,启动的时候不报错,但是使用的时候会报错

下面是Setter方法注入的示例:

@RestController
public class UserController {
    // Setter 注入
    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

Setter注入有什么优缺点:

优点:

  • 完全符合单一职责设计原则,一个Setter只针对一个对象。
  • 允许后续对对象重新注入和配置,比较灵活

缺点:

  • 注入方式要比属性注入麻烦很多
  • 不可注入不可变对象
  • Setter 注入提供了 setXXX 的方法,所以被注入的对象可能随时被修改

下面是构造方法注入的示例:

@RestController
public class UserController {
    // 构造方法注入
    private UserService userService;

    //如果当前类只有一个构造方法,那么这个@Autowire也可以省略
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

构造函数注入有什么优缺点?

优点:

  • 确保依赖不可变:被注入的对象,可以使用final修饰符,以确保这个对象不会被改变
  • 依赖项的强制性注入:当要实例化对象的时候,由于自己实现了有参数的构造函数,所以不会调用默认无参构造函数,那么就需要Spring容器传入所需要的参数,所以就两种情况:

    1. 有该类型的参数->传入,OK 。
    2. 无该类型的参数->报错。
    3. 所以保证依赖对象不会为空,Spring总不至于传一个null进去吧 😦
  • 完全初始化的状态:

    • 这个可以跟上面的依赖不为空结合起来,向构造器传参之前,要确保注入的内容不为空,那么肯定要调用依赖组件的构造方法完成实例化。而在Java类加载实例化的过程中,构造方法是最后一步(之前如果有父类先初始化父类,然后自己的成员变量,最后才是构造方法,这里不详细展开。)。所以返回来的都是初始化之后的状态。
  • 如果有循环依赖,项目启动的时候就会报错提醒你

@Autowired和@Resource的区别

相同点:这俩注解都是属性注入的方式,都是直接写在属性上的

不同点:

  • @Autowired是Spring提供的注解,@Resource是JDK提供的注解(不用导入额外框架也可以使用)
  • @Autowired是根据对象的类型来注入的,如果一个Class创建了两个对象,那么@Autowired就不知道该注入哪一个了,回报错!
  • @Resource有两个属性:name和type

    • 当指定了name的时候,@Resource会根据对象的名字来进行注入
    • 当指定了type的时候,@Resource会更具对象的类型来进行注入
    • 如果都不指定的话,@Resouce会先根据名字注入,找不到名字就使用类型注入

如果非要使用这两个注解的话,那肯定是推荐注入机制更加完善的@Resource

最好的方式其实是使用构造函数注入的方式

参考资料

除非注明,向东的笔记本文章均为原创,本文地址 https://www.mengxiangdong.com/jishu/120.html,转载请以链接形式注明出处。

作者: 简介:

《Spring依赖注入,为什么不推荐用@Autowired,而是用构造函数注入呢?》留言数:0

发表留言