You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用AspectJ拦截构造器调用并替换对象?拦截后对象仍创建的疑问

问题原因分析

你遇到的问题核心在于AspectJ对构造器的execution和call切入点处理逻辑不同,以及构造器本身的JVM执行机制:

  1. 构造器的JVM执行逻辑:当执行new ExampleClass()时,JVM会先完成对象的内存分配(创建出一个未初始化的实例),然后才会调用构造器代码进行初始化。也就是说,在构造器代码(包括切面逻辑)执行之前,对象已经存在了。
  2. execution切入点的行为:execution(ExampleClass.new())匹配的是构造器代码的执行过程。对于构造器的@Around切面,无论你返回什么值,AspectJ都会忽略这个返回值,最终返回JVM已经创建好的那个实例——因为构造器的语义就是返回新创建的对象,AspectJ会遵循这个语义。

所以你在切面里返回null并没有作用,JVM已经提前创建了对象,最终还是会把这个对象返回给调用者。

正确的解决方案

如果你想替换构造器创建的对象,需要使用call切入点来拦截构造器的调用,而不是execution。call切入点匹配的是构造器的调用动作,此时切面的返回值会被用作调用的结果,从而实现对象替换。

修改后的切面代码如下:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AnnotationAspect {

    @Around("call(ExampleClass.new())")
    public Object aroundObjectCreation(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Intercepting object creation call");
        // 这里返回你想要替换的对象,比如自定义实例或者null
        return null;
        // 如果要创建自定义实例,可以这样:
        // return new AnotherClass();
    }
}

此时运行Test类,输出会是:

Intercepting object creation call
null
额外说明
  • 如果你只是想阻止原对象的初始化逻辑(不执行原构造器的代码),在使用call切入点时,不要调用joinPoint.proceed(),这样原构造器就不会被执行,原对象也不会被初始化。
  • 注意call和execution的区别:call是拦截调用构造器的地方,execution是拦截构造器本身的执行过程。对于构造器的对象替换需求,call是正确的选择。

内容的提问来源于stack exchange,提问作者Ivan Jevtic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:12:07