为什么aop类要交给ioc容器管理,并加component

22 阅读2分钟

因为 Spring AOP 的切面(AOP 类)只有在被 Spring 容器“识别并托管”之后,Spring 才能把它织入到目标 Bean 的代理链里。不交给 IOC 管理、不给 @Component,它就只是一个普通 Java 类:Spring 根本不知道它存在,更不可能自动生效。

下面把原因拆开讲透:

1) Spring AOP 是“容器级”的:只对 Spring Bean 起作用

Spring AOP 的基本机制是:

  • 容器创建目标 Bean 时
  • 根据容器里已知的切面/通知
  • 决定是否给这个 Bean 生成代理,并把通知挂到代理链上

所以前提是:

  • 切面本身要在容器里(Spring 才能扫描到它的 @Aspect/@Before/@Around 等信息)
  • 被增强的对象也必须是容器里的 Bean(否则不会被代理)

如果你 new MyAspect(),它不在容器里,Spring 不会去解析它、也不会把它用于织入。

2) 为什么要加 @Component(或其他注册方式)

切面类通常长这样:

@Aspect
@Component
public class LogAspect { ... }
  • @Aspect:告诉 Spring “这是切面,里面有通知/切点”
  • @Component:告诉 Spring “把它当成 Bean 扫描进 IOC 容器”

没有 @Component 时(且你没有用别的方式注册),它不会成为 Bean:

  • Spring 不会创建它
  • 也就不会把它纳入 AOP 解析与织入流程
  • 结果就是:切面不生效

注意:不一定非得 @Component,只要能让它成为 Bean 就行,比如:

  • @Configuration + @Bean 注册
  • XML 配置注册
    但在注解项目里最常见就是 @Component

3) 交给 IOC 管理还能带来什么“额外好处”

除了“能生效”,还有这些现实收益:

(1) 切面也需要依赖注入

切面里经常要用到:

  • RedisTemplate
  • UserContext
  • MeterRegistry
  • HttpServletRequest
    这些都靠 IOC 注入。如果切面不在 IOC,@Autowired 也没用。

(2) 生命周期与单例管理

切面一般是单例(避免每次创建开销)。交给 IOC,Spring 负责:

  • 单例缓存
  • 初始化/销毁
  • 线程安全策略(你自己写切面要避免共享可变状态)

(3) 能参与更复杂的 AOP/事务链

比如同一个方法上同时有:

  • 日志切面
  • 事务切面(@Transactional)
  • 权限切面
    这些需要 Spring 统一排序、组装代理链(@Order 等)。不在容器里就谈不上统一编排。

4) 一个常见误区:@Aspect 不是注册 Bean 的注解

很多人以为只写 @Aspect 就够了——不够。

  • @Aspect 只声明“这是切面”
  • 不会自动把它注册成 Bean

所以一般都要再加 @Component(或用 @Bean 注册)。


小结一句话

Spring AOP 是在 IOC 创建 Bean 的过程中织入的;切面不进 IOC,Spring 不知道它,也就无法织入,自然不生效。