Spring IOC、AOP 注入方式详解:@Autowired 和 @Resource 的区别与应用

你有没有遇到过这样的尴尬:明明用@Autowired注入了,结果报错找不到Bean;换成@Resource又能正常运行;或者AOP切面里注入依赖时,Bean实例不是你想要的那个……其实,这背后隐藏着Spring IOC容器和AOP代理的秘密。今天,我们就来扒一扒@Autowired@Resource的“内心世界”,让你在Spring依赖注入的路上少走弯路。

首先,我们先来了解一下它们!

1. Spring IOC 容器基础知识

1.1 什么是IOC(控制反转)?

控制反转是一种设计思想,指将对象的创建和依赖关系交给容器管理,程序不再主动去new对象,而是由容器负责注入依赖。Spring通过IOC容器实现这一点,极大提升了代码的解耦性和可维护性。

1.2 依赖注入(DI)的两种主要方式
  • 构造器注入:通过构造函数传入依赖,保证依赖不可变,适合必需依赖。
  • Setter注入:通过setter方法注入依赖,适合可选依赖或循环依赖场景。
1.3 Spring IOC容器管理Bean的生命周期

Spring容器负责Bean的实例化、依赖注入、初始化和销毁过程。理解Bean的生命周期有助于理解注入时机和代理对象的生成。


2. 依赖注入注解详解:@Autowired vs @Resource

2.1 @Autowired注解详解
  • 来源:Spring框架自带,定义在org.springframework.beans.factory.annotation.Autowired
  • 注入方式:默认按类型(byType)自动装配
  • 常用属性
    • required(默认true):指定依赖是否必须存在,false时找不到也不会报错
  • 结合@Qualifier使用:当有多个同类型Bean时,通过@Qualifier("beanName")指定注入哪个Bean
  • 支持注入位置
    • 构造器
    • 字段(属性)
    • Setter方法
  • 示例代码
    @Component
    public class UserService {
        @Autowired
        private UserRepository userRepository;
    
        @Autowired(required = false)
        private NotificationService notificationService;
    
        @Autowired
        public UserService(OrderService orderService) {
            this.orderService = orderService;
        }
    }
    2.2 @Resource注解详解
  • 来源:Java标准规范(JSR-250),定义在javax.annotation.Resource
  • 注入方式
    • 默认优先按名称(byName)注入
    • 找不到按类型(byType)注入
  • 常用属性
    • name:指定注入Bean的名称
    • type:指定注入Bean的类型
  • 不支持required属性
  • 支持注入位置
    • 字段
    • Setter方法
  • 示例代码
    @Component
    public class UserService {
        @Resource(name = "userRepository")
        private UserRepository userRepository;
    
        @Resource
        public void setNotificationService(NotificationService notificationService) {
            this.notificationService = notificationService;
        }
    }

 

3. @Autowired 和 @Resource 的核心区别

特性 @Autowired @Resource
所属框架 Spring框架 Java标准(JSR-250)
默认注入方式 按类型(byType) 按名称(byName),找不到按类型
支持属性 required@Qualifier nametype
适用范围 Spring环境 Spring及Java EE环境
注入位置 构造器、字段、Setter方法 字段、Setter方法
多实现Bean处理 需要配合@Qualifier@Primary 通过name属性指定
是否支持循环依赖 支持(通过Setter或字段注入) 支持(通过Setter注入)

4. Spring AOP环境下的注入细节

4.1 AOP代理类型
  • JDK动态代理:基于接口生成代理类,注入接口类型Bean时生效
  • CGLIB代理:基于类继承生成代理类,注入类类型Bean时生效
4.2 代理对注入的影响
  • 使用@Autowired时,默认注入的是代理对象(如果有AOP切面),这意味着调用方法会经过切面逻辑。
  • 使用@Resource注入时,按名称查找Bean,注入的也是代理对象(如果AOP开启)。
  • 需要注意循环依赖和代理失效问题,避免注入原始对象导致切面失效。
4.3 AOP中注入的最佳实践
  • 优先使用接口注入,保证JDK动态代理正常工作
  • 避免在构造器中注入带有AOP代理的Bean,推荐字段或Setter注入
  • 使用@Lazy注解解决循环依赖问题
  • 在复杂场景下,考虑手动获取代理对象(如通过AopContext.currentProxy()

5. 实战示例代码

@Service
public class OrderService {
    @Autowired
    private PaymentService paymentService;

    @Resource(name = "inventoryService")
    private InventoryService inventoryService;

    @Autowired(required = false)
    private NotificationService notificationService;

    public void processOrder(Order order) {
        paymentService.pay(order);
        inventoryService.reserve(order);
        if (notificationService != null) {
            notificationService.notify(order);
        }
    }
}

@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("方法调用前:" + joinPoint.getSignature());
    }
}

6. 总结与建议

  • 如果只关注Spring环境,推荐使用@Autowired,结合@Qualifier精准控制注入。
  • 需要兼容Java EE或其他容器时,@Resource更合适,尤其是按名称注入。
  • AOP场景下,优先接口注入,避免构造器注入代理Bean。
  • 多实现Bean时,合理使用@Primary@Qualifier,避免注入冲突。
  • 养成良好注入规范,提升代码可维护性和稳定性。

你可能感兴趣的:(Spring IOC、AOP 注入方式详解:@Autowired 和 @Resource 的区别与应用)