Spring AOP源码分析(三)

210 阅读8分钟

1.Spring AOP源码分析(三)

1.JDK

如果创建的是JdkDynamicAopProxy,那么当执行目标类的时候,会进入到JdkDynamicAopProxy#invoke。因为JdkDynamicAopProxy本身也是一个InvocationHandler,并实现了invoke方法。

org.springframework.aop.framework.JdkDynamicAopProxy#invoke

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;

    //1.获取目标源
    TargetSource targetSource = this.advised.targetSource;
    Class<?> targetClass = null;
    Object target = null;

    try {
        //2.目标类如果没有实现equals或hashCode,则调用代理类实现的
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            return equals(args[0]);
        }
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            return hashCode();
        }
        //3.可能有多层代理,返回真正的目标类
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        //4.直接通过反射执行方法
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                 method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;

        //5.如果expose-proxy为true,则暴露代理对象
        if (this.advised.exposeProxy) {
            //向AopContext中设置当前代理对象,可以通过AopContext.currentProxy调用
            //可解决某个类中一个方法调用另一个方法,无法执行拦截的问题
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        //6.获取目标对象
        target = targetSource.getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }

        //7.获取适合当前方法的拦截器,通过ClassFilter和MethodMatcher进行匹配,然后缓存,下次直接从缓存中获取
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        //8.如果拦截器为空,则直接执行目标方法
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            //通过反射执行目标方法
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            //9.创建一个方法调用器,并将拦截器链传入当中
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            //10.执行拦截器链
            retVal = invocation.proceed();
        }

        //11.获取方法返回值类型
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            //如果方法返回值为this,即return this,则直接将代理对象赋值给返回值
            retVal = proxy;
        }
        //12.如果返回值是基本数据类型,但是返回了null,则抛出异常
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    }
    finally {
        //13.如果每次不是需要相同的target,则需要释放
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        //14.回滚proxy
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

基于JDK动态代理的方式,首先是一轮判断,如果目标类没有实现equalshashCode,那么在调用这两个方法的时候会调用代理类实现的方法,如果目标类本身就是代理类,那么就需要不断的剥离,拿到真正的目标类,最后一个就是直接执行ProxyConfig的方法;然后就是根据exposeProxy属性判断是否需要暴露当前的Proxy,暴露之后,可以通过AopContext.currentProxy进行调用;然后获取当前目标类可以使用的拦截器,这里也会通过ClassFilterMethodMatcher进行匹配,然后缓存起来,下次直接从缓存中取,这里还包含一个转换,使用的适配器模式;拿到调用链之后,创建ReflectiveMethodInvocatin,并调用proceed方法,执行拦截器链;最后根据方法返回类型返回结果。

这里核心的就是获取Interceptor和执行Interceptor

1.获取Interceptor

org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Advised config, Method method, Class<?> targetClass) {

    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    //1.registry为DefaultAdvisorAdapterRegistry类型,适配器模式,将非Interceptor的Advice转为Interceptor
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    //2.遍历通知器列表
    for (Advisor advisor : config.getAdvisors()) {
        if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            //3.调用ClassFilter对Bean类型进行匹配,无法匹配说明当前通知器不适用于这个bean
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                //4.将advisor中的advice转成相应的拦截器
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                //5.通过方法匹配器对目标方法进行匹配
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    //6.若isRuntime为true,则表明MethodMatch运行时需要做一些检测
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        else if (advisor instanceof IntroductionAdvisor) {
            //7.IntroductionAdvisor类型的通知器,仅需进行类级别的匹配即可
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

首先是一个适配器模式,将Advice转为Interceptor

org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#DefaultAdvisorAdapterRegistry

//注册默认的适配器,将Advice转为Interceptor
public DefaultAdvisorAdapterRegistry() {
    //处理MethodBeforeAdvice
    registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
    //处理AfterReturningAdvice
    registerAdvisorAdapter(new AfterReturningAdviceAdapter());
    //处理MethodBeforeAdvice的异常
    registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

这里只注册了前置处理和后置返回,那其他的三个为什么不需要适配器,原因很简单,看下类图:

可以看到其他的三个通知都是MethodInterceptor的子类,该类提供了一个invoke方法, 这个方法就是每个通知具体的执行逻辑,所以对于没有实现该接口的类,都必须通过适配器模式进行转换。

转换完成之后就很简单了,就是遍历所有的Advisor,根据joinpointClassFilterMethodMatcher进行匹配,匹配合格的则根据Advisor获取Inteceptor,并返回。

2.执行Interceptor

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

@Override
public Object proceed() throws Throwable {
    //1.拦截器执行完成之后,就执行目标方法,通过一个索引进行计数
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        //2.执行目标方法
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        //3.动态匹配目标方法
        InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            //4.匹配失败,忽略当前拦截器,执行下一个拦截器
            return proceed();
        }
    }
    else {
        //5.执行拦截器
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

proceed是AOP执行的核心方法,起到一个分发的作用。通过一个索引计算通知是否执行完了,决定是否可以执行目标方法。一般情况下都是走第5步,这一步执行的invoke方法其实就是之前的Interceptor的方法,并把当前的MethodInvocation作为参数传递。

org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    //执行前置通知逻辑
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    //通过MethodInvocation调用下一个拦截器,若所有拦截器执行完成,则执行目标方法
    return mi.proceed();
}

org.springframework.aop.aspectj.AspectJMethodBeforeAdvice#before

@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
    //调用通知方法
    invokeAdviceMethod(getJoinPointMatch(), null, null);
}

这里调用了一个getJoinPointMatch方法,获取连接点匹配器JoinPointMatch。这个接口提供了两个方法:matchesgetParameterBindings,见名知意,matches用于判断连接点是否匹配,getParameterBindings用于返回通知的方法参数。

org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethod

protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
    //调用通知方法,并向其传递参数
    return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

这里调用了一个argBinding方法,很明显是用来通知方法的参数绑定的。对于目前的五种通知来说,通知方法也就包含以下几种参数:普通参数、JointPoint、返回参数、异常参数。

org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgs

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
    //通过反射调用通知方法
    return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
public void before(){
    System.out.println("前置通知");
}

这就是一个前置通知的执行,有了方法参数、通知方法、切面,然后通过反射执行,然后再回到proceed方法继续执行其他通知。其他的通知都差不多,只是通知和目标方法的顺序不同。

当所有的Interceptor执行之后,调用invokeJoinpoint执行目标方法。

org.springframework.aop.framework.ReflectiveMethodInvocation#invokeJoinpoint

protected Object invokeJoinpoint() throws Throwable {
    return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

org.springframework.aop.support.AopUtils#invokeJoinpointUsingReflection

public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
    throws Throwable {
    ReflectionUtils.makeAccessible(method);
    return method.invoke(target, args);
}

非常简单,通过反射执行目标方法,然后再回滚去执行之前未完成的通知。

2.CGLIB

如果proxy-target-class为true,或者目标类没有实现接口,那么就会使用CglibAopProxyCglibAopProxy内置了一些内部类,用于处理方法的执行。

org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

    private final AdvisedSupport advised;

    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        Class<?> targetClass = null;
        Object target = null;
        try {
            //1.是否需要暴露当前代理
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            target = getTarget();//通过TargetSource获取目标对象
            if (target != null) {
                targetClass = target.getClass();
            }
            //2.将Advice转为Interceptor
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            Object retVal;
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = methodProxy.invoke(target, argsToUse);
            }
            else {
                //3.这是ReflectiveMethodInvocation的子类,是一个内部类
                retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
            }
            retVal = processReturnType(proxy, target, method, retVal);
            return retVal;
        }
        finally {
            if (target != null) {
                releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

这个内部类实现了MethodInterceptor接口,重写了interceptor方法,当代理类执行目标方法的时候就会进入这个方法,这个方法的整体实现和JdkDynamicAopProxy#invoke方法基本一致,主要的区别在于这里使用的CglibMethodInvocation,这个类是ReflectiveMethodInvocation的子类。

org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation

private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

    private final MethodProxy methodProxy;

    private final boolean publicMethod;

    public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
                                 Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

        super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
        this.methodProxy = methodProxy;
        this.publicMethod = Modifier.isPublic(method.getModifiers());
    }

	//执行目标方法
    @Override
    protected Object invokeJoinpoint() throws Throwable {
        if (this.publicMethod) {
            return this.methodProxy.invoke(this.target, this.arguments);
        }
        else {
            return super.invokeJoinpoint();
        }
    }
}

这个类只重写了invokeJoinpoint方法,那也就意味着CglibMethodInvocation调用的proceed方法是ReflectiveMethodInvocation中的方法,也就是和JdkDynamicAopProxy调用的一模一样了。

主要的区别在于目标方法的,如果是public修饰符的方法,则直接通过MethodProxy去执行,否则也是调用ReflectiveMethodInvocation中的invokeJoinpoint执行。

总结一下:

1.分发通知执行的核心方法是一样的,都是ReflectiveMethodInvocation#proceed

2.JDK的invokeCGLIBinterceptor整体流程基本一致。是否需要暴露代理、从TargetSource获取target、将Advice转为Interceptor、执行通知、执行目标方法、处理返回值。

3.目标方法的执行稍有不同,JDK是使用ReflectiveMethodInvocation#invokeJoinpoint,CGLIB是使用CglibMethodInvocation#invokeJoinpoint