面试官:Spring 是在什么时候、在哪里为符合条件的 Bean 创建代理对象的?

针对这个问题,我们可以从“时间点 (When)”和“代码位置 (Where)”两个维度来回答。

时间点 (When): 在 Bean 的生命周期中的“初始化”阶段

Spring AOP 的代理创建过程,深深地嵌入在 Spring Bean 的生命周期中。一个 Bean 的生命周期大致如下:

  1. 实例化 (Instantiation): Spring 通过反射创建出 Bean 的一个空对象。
  2. 属性填充 (Populate Properties): Spring 进行依赖注入,将 @Autowired 等注解标记的依赖设置到 Bean 对象中。
  3. 初始化 (Initialization): 这是一个关键阶段,包含多个步骤。
    • 执行 Aware 接口相关的方法(如 BeanNameAware)。
    • 执行 BeanPostProcessorpostProcessBeforeInitialization 方法。
    • 执行 @PostConstructinit-method 指定的初始化方法。
    • 执行 BeanPostProcessorpostProcessAfterInitialization 方法。 <-- 就是在这里!
  4. 就绪状态 (Ready): Bean 创建完成,放入单例池,可供其他组件使用。

结论: Spring 是在 Bean 完成实例化和属性填充,并且执行完它自身的初始化逻辑之后,通过一个名为 BeanPostProcessor 的钩子来创建代理对象的。

为什么是这个时间点?

因为在这个时间点,原始的目标 Bean 已经是一个完整、可用的对象了。它的所有依赖都已注入,所有初始化配置都已完成。这时对它进行“包装”(创建代理)是最安全、最合适的时机。

代码位置 (Where): 在 BeanPostProcessor 的实现类中

现在我们知道了“时间点”,那么具体是哪段代码在工作呢?

核心角色:BeanPostProcessor

你可以把 BeanPostProcessor 想象成一个 Bean 的“质量检验站”。每个 Bean 在最终“出厂”(放入容器)前,都必须经过这个检验站。检验站可以决定是直接放行这个 Bean,还是对它进行一番“包装和改造”再放行。

具体实现类:AnnotationAwareAspectJAutoProxyCreator

  1. AOP 的总开关:当我们使用 @EnableAspectJAutoProxy 注解时,Spring 会向容器中注册一个名为 AnnotationAwareAspectJAutoProxyCreator 的 Bean。

  2. AOP 的总指挥:这个类就是 AOP 功能的总指挥。它本身就是一个 BeanPostProcessor 的实现。

  3. 关键的拦截方法AnnotationAwareAspectJAutoProxyCreator 继承了 AbstractAutoProxyCreator,其中最核心的方法是 postProcessAfterInitialization()

详细的代码执行路径:

  1. 当一个 Bean(比如你的 UserService)走到了生命周期的第 3 步(初始化之后),Spring 容器会调用 AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization(Object bean, String beanName) 方法。

  2. 这个方法内部会调用一个核心的包装方法 wrapIfNecessary(bean, beanName, cacheKey)。这个方法的名字已经说明了一切:“如果需要,就包装它”。

  3. wrapIfNecessary 方法中,它会执行以下关键操作:
    a. 寻找适用的切面 (Find Advisors):它会调用 getAdvicesAndAdvisorsForBean() 方法,扫描容器中所有的 @Aspect 切面,解析它们的 @Pointcut 表达式,看看有没有哪个切点的规则能匹配上当前这个 UserService Bean 的方法。
    b. 决策 (Decision)
    * 如果没有找到任何可以应用的切面,说明这个 Bean 不需要 AOP 增强。wrapIfNecessary 方法会直接返回原始的 UserService 对象
    * 如果找到了一个或多个适用的切面,说明这个 Bean 需要被代理。

    c. 创建代理 (Create Proxy):程序会继续执行 createProxy() 方法。这个方法会:
    * 创建一个 ProxyFactory(代理工厂)。
    * 将原始的 UserService 对象(作为 target)、所有找到的切面逻辑(Advisors)都设置到工厂里。
    * 由工厂决定使用 JDK 动态代理还是 CGLIB 来生成最终的代理对象

  4. 返回代理对象:最终,postProcessAfterInitialization 方法会返回这个新创建的代理对象。Spring 容器会用这个代理对象替换掉单例池中原始的 UserService 对象。

图解流程

+--------------------------------+
| Spring Container               |
|  (Starts creating UserService) |
+--------------------------------+
          |
          v
+--------------------------------+
| 1. Instantiate UserService   |
+--------------------------------+
          |
          v
+--------------------------------+
| 2. Populate Properties (DI)    |
+--------------------------------+
          |
          v
+--------------------------------+
| 3. Initialize (@PostConstruct) |
+--------------------------------+
          |
          v
+-----------------------------------------------------------------+
| 4. BeanPostProcessor (AnnotationAwareAspectJAutoProxyCreator)   |
|    - postProcessAfterInitialization(userService, "userService") |
|      |                                                          |
|      +--> wrapIfNecessary()                                     |
|           |                                                     |
|           +--> Does any @Pointcut match UserService?            |
|                |              |                                 |
|            (No)|              | (Yes)                           |
|                v              v                                 |
|      Return original bean     createProxy() -> [UserServiceProxy]|
|                               |                                 |
|      <------------------------+---------------------------------+
|                                                                 |
+-----------------------------------------------------------------+
          | (Returns either original bean or proxy)
          v
+--------------------------------+
| 5. UserService (or its Proxy)  |
|    is now ready in the container |
+--------------------------------+

总结

  • When (时间点): 在 Bean 生命周期的初始化阶段之后,通过 BeanPostProcessorpostProcessAfterInitialization 方法。
  • Where (代码位置): 在 AnnotationAwareAspectJAutoProxyCreator 类(由 @EnableAspectJAutoProxy 注册)的 wrapIfNecessary 方法中,该方法会判断是否需要创建代理,并在需要时调用 createProxy 方法来完成创建。

所以,任何脱离了 Spring Bean 生命周期管理的操作(比如手动 new 一个对象),都无法享受到 AOP 的增强,因为它们从未经过这个重要的“质量检验站”。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值