为什么IDEA提示不推荐@Autowired❓️如果使用@Resource呢❓️

前言

在使用 Spring 框架时,依赖注入(DI)是一个非常重要的概念。通过注解,我们可以方便地将类的实例注入到其他类中,提升开发效率。@Autowired又是被大家最为熟知的方式,但很多开发者在使用 IntelliJ IDEA 时,常常看到 IDEA 提示不推荐使用@Autowired,这是为什么呢?今天讲一下我对于@Autowired字段注入的理解。

1. 为什么不推荐使用@Autowired

1.1. 隐式依赖

@Autowired会根据类型自动注入依赖,可能导致依赖不明确。特别是在存在多个符合类型的候选对象时,可能会导致注入失败或错误地注入实例。

1.2. 循环依赖

@Autowired可能导致循环依赖,尤其在单例 Bean 中,虽然 Spring 有解决方案,但仍需额外处理。

1.3. 生命周期不透明

通过@Autowired注入的 Bean 由 Spring 管理,类无法显式了解其生命周期。相比之下,构造器注入可以显式管理依赖的生命周期。

1.4. 不符合不可变性原则

字段注入使得依赖关系在对象生命周期内可能发生变化,而构造器注入确保依赖在对象创建时设定,符合不可变性原则。

经常看到的争议点 :不推荐使用@Autowired,所以就使用@Resource(使用@Resource时,IDEA不会有波浪线提示)。

2. @Autowired@Resource的基本用法

2.1. @Autowired

@Autowired是 Spring 提供的注解,用于自动注入依赖项。Spring 会根据类型 (默认情况下)或者名称 (通过 @Qualifier)来自动注入所需的 Bean。

java 复制代码
@Autowired
private UserService userService;

在这个例子中,Spring 会自动将 UserService 类型的 Bean 注入到 userService 属性中。

2.2. @Resource

@Resource 是 Java 规范的一部分,来自 javax/jakarta.annotation 包,它更注重按照名称来注入 Bean。默认情况下,它会尝试按名称 匹配,但如果没有找到匹配的名称,再通过类型注入。

java 复制代码
@Resource
private UserService userService;

@Autowired不同@Resource会首先查找名为userService的 Bean,如果找不到,再通过类型注入。

可以看出其实两者本质上是没有区别的,只是匹配顺序不一样。

3. @Autowired@Resource实测对比

假如你有一个接口类,如下:

java 复制代码
@Service
public interface UserService {
    // 用户服务...
}

两个实现类:如下:

java 复制代码
@Component
public class UserServiceImpl implements UserService {
    // 实现细节
}

@Component
public class AnotherUserServiceImpl implements UserService {
    // 另一个实现
}
3.1. 使用@Autowired做测试

在测试接口里面加入@Autowired,如下:

java 复制代码
/**
 * 测试接口
 */
@RestController("test")
public class TestController {  
    @Autowired
    private UserService userService;
}

启动项目,控制台输出错误,如下:

错误提示:需要一个bean,但是找到了两个bean。

修改之后指定具体的bean名,如下:

java 复制代码
@RestController("test")
public class TestController {  
    @Autowired
    //	@Qualifier("userServiceImpl")  // 或者使用Qualifier来指定bean名
    private UserService userServiceImpl;
}

启动项目,项目正常启动,断点测试如下:

正常获取到需要的bean实例。

3.2. 使用@Resource做测试

在测试接口里面加入@Resource,如下:

java 复制代码
/**
 * 测试接口
 */
@RestController("test")
public class TestController {
    @Resource
    private UserService userService;
}

启动项目,控制台输出错误,如下:

错误提示:需要一个bean,但是找到了两个bean。

修改之后指定具体的bean名,如下:

java 复制代码
@RestController("test")
public class TestController {  
    @Resource
     // @Resource(name = "userServiceImpl")  // 或者使用name来指定bean名
    private UserService userServiceImpl;
}

启动项目,项目正常启动,断点测试如下:

正常获取到需要的bean实例。

可以看出实际上@Autowired@Resource的使用效果是一样的。(@Resource并不优于@Autowired,两者都是基于字段注入。甚至于在Spring框架中,@Autowired性能更好,例如:自动装配的细粒度控制 。)

4. 推荐注入的方式

构造器注入是推荐的首选方式,尤其在处理复杂依赖关系、不可变对象、单元测试等场景时,构造器注入非常有用。

4.1. 推荐原因
  • 显式依赖关系:构造器注入使依赖关系在对象创建时就显式地列出,代码更清晰。
  • 不可变性 :依赖可以声明为 final,避免修改。
  • 避免循环依赖:能及时发现并避免循环依赖问题。
  • 明确依赖关系:构造器清晰暴露依赖,增强代码可读性。
4.2. 示例
java 复制代码
@RestController("test")
public class TestController {
    private final UserService userService;

    public TestController(UserService userServiceImpl) {
        this.userService = userServiceImpl;
    }
}

// 或者使用lombok简化代码。
@RestController("test")
@RequiredArgsConstructor
public class TestController {
    private final UserService userServiceImpl;
}

伪逻辑说明

  • 显式依赖关系
    应该关注的是,整个项目的代码规范,而不是针对具体的某一个类去优化,使用构造器注入。
  • 不可变性
    应该关注的是,合理的设计,项目中bean在初始时,如果使用@Autowired注入某个类,就应该不在初始化期间去修改它。
  • 避免循环依赖
    也是和项目的架构相关,如果无法中设计上避免,也可以通过代理和懒加载去解决。
  • 明确依赖关系
    如果项目类名命名规范,不使用相同的类名,或者使用一些前缀后缀去区分,也能够不影响依赖关系。

5. 构造器一定优于@Autowired吗?

@Autowired在一些方面要优于构造器注入?

  1. 简化代码:自动注入依赖,无需手动编写构造器或 setter 方法,代码更简洁。

  2. 快速开发:灵活且快速,不需要修改构造函数,可以直接通过字段注入依赖。

  3. 自动依赖管理:Spring 自动管理依赖,简化了依赖的选择和注入过程。

  4. 避免构造函数冗长:对于依赖较多的类,字段注入避免了构造函数过长的问题。

综合来看@Autowired依旧是最主流的注入方式。

结语

虽然 IDEA 提示不推荐使用 @Autowired,但这并不意味着它是一个糟糕的选择。不同的注入方式有其各自的优缺点,选择依赖注入方式时,应该根据项目规模、复杂性以及团队编码习惯来决定,而不是盲目跟随趋势。

相关推荐
null or notnull16 分钟前
idea对jar包内容进行反编译
java·ide·intellij-idea·jar
言午coding1 小时前
【性能优化专题系列】利用CompletableFuture优化多接口调用场景下的性能
java·性能优化
幸好我会魔法2 小时前
人格分裂(交互问答)-小白想懂Elasticsearch
大数据·spring boot·后端·elasticsearch·搜索引擎·全文检索
危险、2 小时前
Spring Boot 无缝集成SpringAI的函数调用模块
人工智能·spring boot·函数调用·springai
SomeB1oody2 小时前
【Rust自学】15.2. Deref trait Pt.1:什么是Deref、解引用运算符*与实现Deref trait
开发语言·后端·rust
缘友一世2 小时前
JAVA设计模式:依赖倒转原则(DIP)在Spring框架中的实践体现
java·spring·依赖倒置原则
何中应2 小时前
从管道符到Java编程
java·spring boot·后端
SummerGao.3 小时前
springboot 调用 c++生成的so库文件
java·c++·.so
组合缺一3 小时前
Solon Cloud Gateway 开发:Route 的过滤器与定制
java·后端·gateway·reactor·solon
SomeB1oody3 小时前
【Rust自学】15.4. Drop trait:告别手动清理,释放即安全
开发语言·后端·rust