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

如何在建造者模式方法链末尾通过切面注入代码?

如何通过切面在建造者方法链末尾自动注入代码(执行build方法)

可以实现这个需求,核心思路是通过切面拦截建造者的所有withXXX方法,判断当前调用是否为方法链的最后一步,随后自动触发build()或其他自定义逻辑。下面提供两种落地方案:

方案一:基于Spring AOP的实现(Spring环境)

1. 切面代码实现

利用Spring AOP的环绕通知拦截建造者的withXXX方法,通过调用栈判断是否为方法链的最终调用:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuilderAutoBuildAspect {

    // 拦截Builder接口及其实现类的所有with开头方法
    @Around("execution(com.yourpackage.Builder+.with*(..))")
    public Object interceptWithMethods(ProceedingJoinPoint joinPoint) throws Throwable {
        // 执行原方法,获取返回的Builder实例
        Builder result = (Builder) joinPoint.proceed();
        
        // 检查调用栈,判断是否存在后续的withXXX方法调用
        boolean isLastCall = true;
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement element : stackTrace) {
            if (element.getMethodName().startsWith("with") 
                && element.getClassName().equals(Builder.class.getName())) {
                isLastCall = false;
                break;
            }
        }
        
        // 是最后一步则自动执行build
        if (isLastCall) {
            result.build();
        }
        
        return result;
    }
}

2. 注意事项

  • 建造者对象需由Spring容器管理,或通过Spring代理生成
  • 若方法链被拆分为多段(如中间赋值给变量),调用栈判断会失效,此时可改用线程本地变量记录调用状态,标记当前是否处于方法链连续调用中

方案二:基于动态代理的通用实现(非Spring环境)

不依赖Spring时,直接用JDK动态代理包裹建造者对象,在代理逻辑中自动触发build():

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class AutoBuildBuilderProxy implements InvocationHandler {
    private final Builder target;

    private AutoBuildBuilderProxy(Builder target) {
        this.target = target;
    }

    public static Builder createProxy(Builder target) {
        return (Builder) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                new Class[]{Builder.class},
                new AutoBuildBuilderProxy(target)
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().startsWith("with")) {
            // 执行原方法
            method.invoke(target, args);
            
            // 判断是否为方法链最后一步
            boolean isLastCall = true;
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            for (StackTraceElement element : stackTrace) {
                if (element.getMethodName().startsWith("with") 
                    && element.getClassName().equals(Builder.class.getName())) {
                    isLastCall = false;
                    break;
                }
            }
            
            if (isLastCall) {
                target.build();
            }
            return proxy; // 返回代理对象维持方法链
        } else if ("build".equals(method.getName())) {
            return method.invoke(target, args);
        }
        return method.invoke(target, args);
    }
}

使用方式:

// 生成带自动build逻辑的代理建造者
Builder builder = AutoBuildBuilderProxy.createProxy(createBuilder());
// 调用方法链,无需显式调用build
builder.withArg2(arg2).withArg10(arg10);

核心问题说明

  • 方法链末尾判断:上述方案采用调用栈分析,是最轻量化的实现;若需更高精度,可结合字节码工具(如ASM)或在建造者内部添加状态标记,但复杂度会提升
  • 线程安全:若建造者为多线程共享对象,需确保状态标记的线程隔离(如用ThreadLocal)
  • 类代理兼容:JDK动态代理仅支持接口,若使用具体建造者类,需改用CGLIB代理实现

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:57:48