AOP源码解析三 方法增强

1,776 阅读5分钟

前言

会更新AOP 系列源码文章 主要更新目录

图片.png

篇幅问题 会分章程更新

方法增强

main() 函数中调用用户方法,会进入代理对象的 invoke 方法

JdkDynamicAopProxy 类中的 invoke 方法是真正执行代理方法

// proxy:代理对象,method:目标对象的方法,args:目标对象方法对应的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;

    // advised 就是初始化 JdkDynamicAopProxy 对象时传入的变量
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    try {
        // 条件成立说明代理类实现的接口没有定义 equals 方法,并且当前 method 调用 equals 方法,
        // 就调用 JdkDynamicAopProxy 提供的 equals 方法
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            return equals(args[0]);
        } //.....

        Object retVal;
		// 需不需要暴露当前代理对象到 AOP 上下文内
        if (this.advised.exposeProxy) {
            // 【把代理对象设置到上下文环境】
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // 根据 targetSource 获取真正的代理对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 查找【适合该方法的增强】,首先从缓存中查找,查找不到进入主方法【下文详解】
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// 拦截器链是空,说明当前 method 不需要被增强
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            // 有匹配当前 method 的方法拦截器,要做增强处理,把方法信息封装到方法调用器里
            MethodInvocation invocation =
                new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 【拦截器链驱动方法,核心】
            retVal = invocation.proceed();
        }

        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
          	// 如果目标方法返回目标对象,这里做个普通替换返回代理对象
            retVal = proxy;
        }
        
        // 返回执行的结果
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        // 如果允许了提前暴露,这里需要设置为初始状态
        if (setProxyContext) {
            // 当前代理对象已经完成工作,【把原始对象设置回上下文】
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass):查找适合该方法的增强,首先从缓存中查找,获取通知时是从全部增强中获取适合当前类的,这里是从当前类的中获取适合当前方法的增强

  • AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance():向容器注册适配器,可以将非 Advisor 类型的增强,包装成为 Advisor,将 Advisor 类型的增强提取出来对应的 MethodInterceptor

    • instance = new DefaultAdvisorAdapterRegistry():该对象向容器中注册了 MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter 三个适配器

    • Advisor 中持有 Advice 对象

      public interface Advisor {
      	Advice getAdvice();
      }
      
  • advisors = config.getAdvisors():获取 ProxyFactory 内部持有的增强信息

  • interceptorList = new ArrayList<>(advisors.length):拦截器列表有 5 个,1 个 ExposeInvocation和 4 个增强器

  • actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()):真实的目标对象类型

  • Boolean hasIntroductions = null:引介增强,不关心

  • for (Advisor advisor : advisors)遍历所有的 advisor 增强

  • if (advisor instanceof PointcutAdvisor):条件成立说明当前 Advisor 是包含切点信息的,进入匹配逻辑

    pointcutAdvisor = (PointcutAdvisor) advisor:转成可以获取到切点信息的接口

    if(config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)):当前代理被预处理,或者当前被代理的 class 对象匹配当前 Advisor 成功,只是 class 匹配成功

    • mm = pointcutAdvisor.getPointcut().getMethodMatcher():获取切点的方法匹配器,不考虑引介增强

    • match = mm.matches(method, actualClass)静态匹配成功返回 true,只关注于处理类及其方法,不考虑参数

    • if (match):如果静态切点检查是匹配的,在运行的时候才进行动态切点检查,会考虑参数匹配(代表传入了参数)。如果静态匹配失败,直接不需要进行参数匹配,提高了工作效率

      interceptors = registry.getInterceptors(advisor):提取出当前 advisor 内持有的 advice 信息

      • Advice advice = advisor.getAdvice():获取增强方法

      • if (advice instanceof MethodInterceptor):当前 advice 是 MethodInterceptor 直接加入集合

      • for (AdvisorAdapter adapter : this.adapters)遍历三个适配器进行匹配(初始化时创建的),匹配成功创建对应的拦截器返回,以 MethodBeforeAdviceAdapter 为例

        if (adapter.supportsAdvice(advice)):判断当前 advice 是否是对应的 MethodBeforeAdvice

        interceptors.add(adapter.getInterceptor(advisor)):条件成立就往拦截器链中添加 advisor

        • advice = (MethodBeforeAdvice) advisor.getAdvice()获取增强方法
        • return new MethodBeforeAdviceInterceptor(advice)封装成 MethodBeforeAdviceInterceptor 返回

      interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)):向拦截器链添加动态匹配器

      interceptorList.addAll(Arrays.asList(interceptors)):将当前 advisor 内部的方法拦截器追加到 interceptorList

  • interceptors = registry.getInterceptors(advisor):进入 else 的逻辑,说明当前 Advisor 匹配全部 class 的全部 method,全部加入到 interceptorList

  • return interceptorList:返回 method 方法的拦截器链

retVal = invocation.proceed():拦截器链驱动方法

  • if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1):条件成立说明方法拦截器全部都已经调用过了(index 从 - 1 开始累加),接下来需要执行目标对象的目标方法

    return invokeJoinpoint()调用连接点(目标)方法

  • this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)获取下一个方法拦截器

  • if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher):需要运行时匹配

    if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)):判断是否匹配成功

    • return dm.interceptor.invoke(this):匹配成功,执行方法
    • return proceed():匹配失败跳过当前拦截器
  • return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)一般方法拦截器都会执行到该方法,此方法内继续执行 proceed() 完成责任链的驱动,直到最后一个 MethodBeforeAdviceInterceptor 调用前置通知,然后调用 mi.proceed(),发现是最后一个拦截器就直接执行连接点(目标方法),return 到上一个拦截器的 mi.proceed() 处,依次返回到责任链的上一个拦截器执行通知方法

图示先从上往下建立链,然后从下往上依次执行,责任链模式

  • 正常执行:(环绕通知)→ 前置通知 → 目标方法 → 后置通知 → 返回通知

  • 出现异常:(环绕通知)→ 前置通知 → 目标方法 → 后置通知 → 异常通知

  • MethodBeforeAdviceInterceptor 源码:

    public Object invoke(MethodInvocation mi) throws Throwable {
        // 先执行通知方法,再驱动责任链
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        // 开始驱动目标方法执行,执行完后返回到这,然后继续向上层返回
        return mi.proceed();
    }
    

    AfterReturningAdviceInterceptor 源码:没有任何异常处理机制,直接抛给上层

    public Object invoke(MethodInvocation mi) throws Throwable {
        // 先驱动责任链,再执行通知方法
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }
    

    AspectJAfterThrowingAdvice 执行异常处理:

    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            // 默认直接驱动责任链
            return mi.proceed();
        }
        catch (Throwable ex) {
            // 出现错误才执行该方法
            if (shouldInvokeOnThrowing(ex)) {
                invokeAdviceMethod(getJoinPointMatch(), null, ex);
            }
            throw ex;
        }
    }
    

本文正在参加「金石计划 . 瓜分6万现金大奖」