前语

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

AOP源码解析三 方法增强

篇幅问题 会分规章更新

办法增强

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万现金大奖」