为什么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,但这并不意味着它是一个糟糕的选择。不同的注入方式有其各自的优缺点,选择依赖注入方式时,应该根据项目规模、复杂性以及团队编码习惯来决定,而不是盲目跟随趋势。

相关推荐
m0_587383002 小时前
广州 24 小时自助健身房解决方案技术实现与实战指南
java·spring·小程序·架构·需求分析
·云扬·3 小时前
Prompt 工程与安全:从 System 设计到注入防御
java·人工智能·安全·ai·prompt
代码不停3 小时前
自动化测试(java)
java·开发语言·selenium·自动化
行百里er4 小时前
Redis 完结篇——Redis 热点问题在 Spring Boot 项目中实战
redis·后端
高频因子挖掘机5 小时前
只取最近 60 个交易日,却每次拉全历史:量化脚本变慢的原因与改法
后端·github·api
鬼手点金5 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github
孟健6 小时前
从5000亿Token到83%字节匹配:AI逆向工程与重构的工程闭环实践
后端·架构·ai编程
paopaokaka_luck6 小时前
滑雪场管理系统(AI智能助手流式对话,ECharts 运营数据分析、教练、雪具与场地一体化预约,钱包支付退款、订单核销与服务评价)
java·人工智能·spring boot·网络协议·数据分析·echarts
SL_staff6 小时前
JVS混合架构实践:能力引擎+动态模型如何支撑企业级可持续交付
spring boot·低代码·全栈
码事漫谈6 小时前
丢得静悄悄,谈一谈 Agent 的记忆是怎么没的
后端