因为 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) 切面也需要依赖注入
切面里经常要用到:
RedisTemplateUserContextMeterRegistryHttpServletRequest
这些都靠 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 不知道它,也就无法织入,自然不生效。