apisdk-starter自动装配组件之Spring Aop源码拓展

文章介绍了如何抽取SpringAop的源码来创建代理对象,实现请求参数的动态调整和失败重试机制。核心在于Aop的前置通知,通过MethodBeforeArgsChangeableAdvice接口和相关适配器、拦截器实现SdkContext参数的构建,确保SDK在非Spring环境中也能正常运行。JdkDynamicAopProxy用于创建原始类的代理,处理AOP相关的拦截动作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

apisdk-starter aop实现部分

  1. 抽取spring aop的源码,用aop的JdkDynamicAopProxy创建原始类的代理对象,即FactoryBean#getObject方法返回的对象,这样可以做到执行原始类的方法时,查找增强类的代理对象,发起Http请求,同时在这里做了失败重试的机制
  2. 拓展参数可变的前置通知,用于SdkContext参数的构建,本质是调用了RegionMock、SecretMock和TokenMock服务,然后把SdkContext参数追加到请求参数中

Spring Aop

看这个分享的应该都用过Spring Aop,这里就不再过多介绍了它是什么了。

我抽取了Spring Aop的部分源码,通过它实现请求参数可变拦截,同时apisdk离开Spring框架,仍然可以正常运行。

讲拦截也好,通知也罢,大家知道是什么意思就行了,不需要纠结这个叫法。

apisdk应用Aop的关键代码如下:

核心拓展类

利用Aop的前置通知,拓展了前置参数可变通知,原理是在运行的过程中,动态封装请求上下文SdkContext参数,变更请求参数。

在这里插入图片描述

上面圈的类是参照Aop的代码结构,拓展出的通知,描述如下:

  • MethodBeforeArgsChangeableAdvice:需要开发者实现的接口,在apisdk中唯一实现SdkContextArgsBeforeChangeableAdvice,实现了SdkContext的构建
  • MethodBeforeChangeableAdviceAdapter:适配器,把开发者实现的MethodBeforeArgsChangeableAdvice交给底层去执行,是框架执行开发者代码的入口
  • MethodBeforeChangeableAdviceInterceptor:执行开发者的MethodBeforeArgsChangeableAdvice,最后把结果添加到方法参数上
  • SdkContextArgsBeforeChangeableAdvice:MethodBeforeArgsChangeableAdvice的唯一实现,实现了SdkContext的关键代码

核心代码

SdkContext自动封装

public class SdkContextArgsBeforeChangeableAdvice implements MethodBeforeArgsChangeableAdvice {
    @Override
    public Object before(Method method, Object[] args, Object target) throws Throwable {

        // 判断执行的方法是否需要自动注入 SdkContext
        // 如果用户的接口声明的方法参数有 SdkContext,则说明用户要手动创建,否则底层自动创建
        boolean isAutoType = MethodWrapperCache.isAutoType(method);

        if (isAutoType) {
            // SdkContextManager 封装了域名、secret、token等服务的调用
            SdkContextManager instance = SdkContextManager.getInstance();
            SdkContext sdkContext = instance.getSdkContext();
            return sdkContext;
        }
        return null;
    }
}

动态调整请求参数

MethodBeforeChangeableAdviceInterceptor

public class MethodBeforeChangeableAdviceInterceptor implements MethodInterceptor, BeforeAdvice {
    private MethodBeforeArgsChangeableAdvice advice;
    public MethodBeforeChangeableAdviceInterceptor(MethodBeforeArgsChangeableAdvice advice) {
        this.advice = advice;
    }
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        // 调用开发者的 MethodBeforeArgsChangeableAdvice
        Object arg = this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        if (arg != null && mi instanceof ReflectiveMethodInvocation) {
            // 将 MethodBeforeArgsChangeableAdvice 返回的结果,添加到调用方法
            ((ReflectiveMethodInvocation) mi).appendArgument(arg);
        }
        return mi.proceed();
    }
}

ReflectiveMethodInvocation#appendArgument

public class ReflectiveMethodInvocation implements MethodInvocation {
    // 方法参数
    protected Object[] arguments;
    // 调整方法请求参数
    public void appendArgument(Object obj) {
        if (this.arguments != null && this.arguments.length > 0) {
            int length = this.arguments.length;
            Object[] newArgs = new Object[length + 1];
            System.arraycopy(this.arguments, 0, newArgs, 0, length);
            newArgs[length] = obj;
            this.arguments = newArgs;
        } else {
            this.arguments = new Object[1];
            this.arguments[0] = obj;
        }
    }
}

Jdk 动态代理

原始接口A和增强接口B,他们的实例化必须由动态代理支持。apisdk有SdkManager和JdkDynamicAopProxy两个代理对象生成器,SdkManager是原代码中就有的,JdkDynamicAopProxy是我参考Spring aop拓展的。

二开后,SdkManager用于生成B的代理对象,JdkDynamicAopProxy用于生成A的代理对象,并且配置了一系列的拦截动作。

开发逻辑:开发者使用A的代理对象,调用方法,底层执行A方法,执行拦截动作,再拿到B的代理对象,执行B的方法。

JdkDynamicAopProxy代码如下:

public class JdkDynamicAopProxy implements InvocationHandler {
    // 包装被代理的对象,每个被代理的对象都有一组Advice
    private AdvisedSupport advised;
    public JdkDynamicAopProxy(AdvisedSupport advised) {
        this.advised = advised;
    }
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advised.getProxiedInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 获取被代理的对象
        Object target = advised.getTarget();
        // 获取 Method 匹配的所有 Advice
        List<Object> chain = this.advised.getInterceptors(method, target.getClass());
        Object retVal;
        if (chain.isEmpty()) {
            // 没有 Advice,直接执行 Method
            retVal = method.invoke(target, args);
        } else {
            // 递归调用 Advice
            ReflectiveMethodInvocation reflectiveMethodInvocation = new ReflectiveMethodInvocation(proxy, target, method, args, chain);
            retVal = reflectiveMethodInvocation.proceed();
        }
        return retVal;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值