Spring源码深度解析(郝佳)-学习-源码解析-aop基于cglib代理调用实现(六)

前面五篇博客己经详细分析了注解如何解析,切面表达式如何解析,切面表达式如何与目标方法匹配,以及生成动态代理,今天,我们来分析一下,代理生成了,方法又是如何调用的呢?方法调用的顺序又是如何控制的呢?先看下面示例代码。

AserviceImpl.java
@Service
public class AserviceImpl {
    public void b(String x, String y) {
        System.out.println("print x=" + x + ",y=" + y);
    }
}
AspectJTest.java
@Aspect
public class AspectJTest {

    @Pointcut("execution(* com.spring_1_100.test_61_70.test65_1.*.*(..)) && args(..)")
    public void test() {

    }

    @Before("test()")
    public void abeforeTest(JoinPoint jp) {
        System.out.println("abeforeTest" + JSON.toJSONString(jp.getArgs()));
    }


    @Before("test()")
    public void beforeTest() {
        System.out.println("beforeTest");
    }


    @After("test()")
    public void afterTest() {
        System.out.println("afterTest()");
    }


    @After("test()")
    public void bafterTest() {
        System.out.println("bafterTest()");
    }


    @AfterReturning("test()")
    public void AfterReturning() {
        System.out.println("AfterReturning()");
    }


    @AfterThrowing(pointcut = "test()", throwing = "e")
    public void afterThrowing(Exception e) {
        System.out.println("异常通知");
        System.out.println(e.getMessage());
    }

    @Around("test()")
    public Object aroundTest(ProceedingJoinPoint p) {
        System.out.println("around before1");
        Object o = null;
        try {
            o = p.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around after1");
        return o;
    }
}
spring65_1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
    <context:annotation-config></context:annotation-config>
    <context:component-scan base-package="com.spring_1_100.test_61_70.test65_1"></context:component-scan>
    <bean id="aservice" class="com.spring_1_100.test_61_70.test65_1.AserviceImpl"></bean>
    <bean class="com.spring_1_100.test_61_70.test65_1.AspectJTest"></bean>
</beans>
测试:
public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring_1_100/config_61_70/spring65_1.xml");
    AserviceImpl service = (AserviceImpl) ac.getBean("aservice");
    service.b("quyixiao", "hukaiming");
}

在这里插入图片描述

########### DynamicAdvisedInterceptor.java

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 {
        if (this.advised.exposeProxy) {
            //如果配置了 expose-proxy="true",取出当前线程中的代理对象,并保存proxy对象到当前线程中
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        target = getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }
        //获取拦截器链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        //如果拦截器链为空,并且当前方法是 public 类型
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            //反射调用该方法
            retVal = methodProxy.invoke(target, args);
        }
        else {
           	//创建cglib方法调用,进入调用链
            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) {
            //恢复之前代理
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

        上述的实现与 JDK 方式实现代理中的 invoke 方法大同小异,都是首先构造链,然后封装此链进行串联调用,稍有区别就是在 jdk 中直接构造 ReflectiveMethodInvocation,而在 cglib 中使用 CglibMethodInvocation继承自ReflectiveMethodInvocation,但是 proceed 方法并没有重写。
########### ReflectiveMethodInvocation.java

public Object proceed() throws Throwable {
    //currentInterceptorIndex初始化值为-1,拦截器每调用一次,值++,当拦截器都调用完,则调用目标类的目标方法
    //也就是AserviceImpl.b()方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }
	//每调用一次,currentInterceptorIndex值++ 
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        //动态代理在这里调用
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            //如果动态代理方法匹配失败,进行下一个拦截器的调用
            return proceed();
        }
    }
    else {
        //对于系统默认的ExposeInvocationInterceptor.ADVISOR拦截器,不是InterceptorAndDynamicMethodMatcher子类 ,因此被调用,可能静态代理就是在这一行代码调用
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}
ExposeInvocationInterceptor.java
public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

ExposeInvocationInterceptor是调用链中的第一个调用拦截器,在这个类中,设置吊起之前的 invocation, 设置当前的 invocation ,在方法调用结束后,恢复之前的 invocation。

AspectJExpressionPointcut.java
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
    checkReadyToMatch();
    //目标类 A继承类 B ,B 中声明了 b 方法,调用A.b()方法,此时getMostSpecificMethod()获取到的是
    // B.b()方法,而不是 A的 b方法
    ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
    //上面的情况,此时获取到的是 A.b()方法的 Shadow
    ShadowMatch originalShadowMatch = getShadowMatch(method, method);

    //ReflectiveMethodInvocation对象
    ProxyMethodInvocation pmi = null;
    //代理对象
    Object targetObject = null;
    //目标类对象
    Object thisObject = null;
    try {
        MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
        targetObject = mi.getThis();
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        pmi = (ProxyMethodInvocation) mi;
        thisObject = pmi.getProxy();
    }
    catch (IllegalStateException ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Could not access current invocation - matching with limited context: " + ex);
        }
    }

    try {
        JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
		/ * *做最后检查,看是否有任何这种(TYPE)残基匹配。为此,我们使用原始方法(代理方法)的阴影来
		确保正确地检查了“ this”。如果不进行此检查,则我们在this(TYPE)上的匹配不正确,其中TYPE匹配目标
		类型,但不是'this'(就像JDK动态代理一样)。
		有关原始错误,请参阅SPR-2979。 * /
        if (pmi != null) { 
        	//A类继承 B 类,A类调用 B 类中的 b 方法,
	        //我们称 B.b()方法称真实方法,称 A.b()方法为目标方法,这里对目标方法匹配
            RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
            if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
            	//如果匹配失败,跳过调用链
                return false;
            }
            //对真实方法再匹配,如果匹配成功,设置绑定参数
            if (joinPointMatch.matches()) {
                bindParameters(pmi, joinPointMatch);
            }
        }
        return joinPointMatch.matches();
    }
    catch (Throwable ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
                    " - falling back to non-match", ex);
        }
        return false;
    }
}
ShadowMatchImpl.java
public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
	//如果Shadow的alwaysFalse为 false 直接不匹配
    if (neverMatches()) {
        return JoinPointMatchImpl.NO_MATCH;
    }
    //再做残存测试
    if (new RuntimeTestEvaluator(residualTest, thisObject, targetObject, args, this.matchContext).matches()) {
	    //如果匹配成功,绑定方法参数名,参数类型,参数值
        return new JoinPointMatchImpl(getPointcutParameters(thisObject, targetObject, args));
    } else {
        return JoinPointMatchImpl.NO_MATCH;
    }
}
RuntimeTestEvaluator.java
public RuntimeTestEvaluator(Test aTest, Object thisObject, Object targetObject, Object[] args, MatchingContext context) {
    this.test = aTest;
    this.thisObject = thisObject;
    this.targetObject = targetObject;
    this.args = args;
    this.matchContext = context;
}
public boolean matches() {
    test.accept(this);
    return matches;
}
Literal.java
public void accept(ITestVisitor v) {
    v.visit(this);
}
RuntimeTestEvaluator.java
public void visit(Literal literal) {
    if (literal == Literal.FALSE) {
        matches = false;
    } else {
        matches = true;
    }
}

上面的 matchs 方法匹配过程中,看上去非常复杂,调来调动,而透过现在看本质,其实就是看residualTest这个对象的 true 或者 false 类型而已。

RuntimeTestEvaluator.java
private PointcutParameter[] getPointcutParameters(Object thisObject, Object targetObject, Object[] args) {
    Var[] vars = state.vars;
    PointcutParameterImpl[] bindings = new PointcutParameterImpl[params.length];
    for (int i = 0; i < bindings.length; i++) {
    	//绑定参数名,参数类型
        bindings[i] = new PointcutParameterImpl(params[i].getName(), params[i].getType());
        //绑定方法参数的值,也就是获取args[i]的值
        bindings[i].setBinding(((ReflectionVar) vars[i]).getBindingAtJoinPoint(thisObject, targetObject, args, subject,
                withinCode, withinType));
    }
    return bindings;
}
AspectJExpressionPointcut.java
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
    if (shadowMatch instanceof DefensiveShadowMatch) {
        return new RuntimeTestWalker(((DefensiveShadowMatch) shadowMatch).primary);
    }
    return new RuntimeTestWalker(shadowMatch);
}
RuntimeTestWalker.java
public RuntimeTestWalker(ShadowMatch shadowMatch) {
    try {
        ReflectionUtils.makeAccessible(residualTestField);
        //获取shadowMatch的residualTest属性
        this.runtimeTest = (Test) residualTestField.get(shadowMatch);
    }
    catch (IllegalAccessException ex) {
        throw new IllegalStateException(ex);
    }
}
public boolean testThisInstanceOfResidue(Class<?> thisClass) {
    return (this.runtimeTest != null &&
            new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest));
}
ThisInstanceOfResidueTestVisitor.java
private static class ThisInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
	
    public ThisInstanceOfResidueTestVisitor(Class<?> thisClass) {
        super(thisClass, true, THIS_VAR);
    }

    public boolean thisInstanceOfMatches(Test test) {
        return instanceOfMatches(test);
    }
}
InstanceOfResidueTestVisitor.java
private final Class<?> matchClass;

private boolean matches;

private final int matchVarType;

public InstanceOfResidueTestVisitor(Class<?> matchClass, boolean defaultMatches, int matchVarType) {
    this.matchClass = matchClass; //设置匹配目标类
    this.matches = defaultMatches;//设置默认匹配为 true 
    this.matchVarType = matchVarType;
}

public boolean instanceOfMatches(Test test) {
    test.accept(this);
    return this.matches;//返回默认匹配类型
}
Literal.java
public void accept(ITestVisitor v) {
    v.visit(this);
}
TestVisitorAdapter.java
@Override
public void visit(Literal literal) {
	
}

程序运行到这里,也是看得一头雾水,不知道testThisInstanceOfResidue()要做些什么,其实抛开很多的其他不重要的代码,先反射调用获取目标方法的 shadow 的residualTest属性值,再获取该属性值true 或false 属性。如果没有获取到,直接返回默认属性 true。

AspectJExpressionPointcut.java
private void bindParameters(ProxyMethodInvocation invocation, JoinPointMatch jpm) {
	//表达式绑定jmp
    invocation.setUserAttribute(getExpression(), jpm);
}
ReflectiveMethodInvocation.java
public void setUserAttribute(String key, Object value) {
    if (value != null) {
        if (this.userAttributes == null) {
            this.userAttributes = new HashMap<String, Object>();
        }
        //以切面表达式为 key, JoinPointMatch 为 value ,保存到 userAttributes 中
        this.userAttributes.put(key, value);
    }
    else {
        if (this.userAttributes != null) {
            this.userAttributes.remove(key);
        }
    }
}

上面的所有调用,都是关系 matchs 方法匹配,如果匹配成功,将方法的参数绑定到JoinPointMatch中。

AspectJAfterThrowingAdvice.java
public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        return mi.proceed();
    }
    catch (Throwable t) {
	    //@AfterThrowing(pointcut = "test()", throwing = "e")
	    //public void afterThrowing(Exception e) 
	    //较验抛出的异常是不是我们方法参数中异常类或子孙类
        if (shouldInvokeOnThrowing(t)) {
        	//调用 afterThrowing 的切点方法
            invokeAdviceMethod(getJoinPointMatch(), null, t);
        }
        throw t;
    }
}
AfterReturningAdviceInterceptor.java
public Object invoke(MethodInvocation mi) throws Throwable {
    Object retVal = mi.proceed();
    //调用 afterReturning 的切点方法
    this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
    return retVal;
}
AspectJAfterAdvice.java
public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        return mi.proceed();
    }
    finally {
     	//调用 after切点方法
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }
}
AspectJAroundAdvice.java
public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    //调用Around切点方法,方法后面两个参数为什么为空?第一个参数是 return 值,
    //第二个参数是目标方法执行所抛出异常,在切点方法around执行时,还没有执行目标方法,因此,这两个参数值为空
    //Before切点也类似
    return invokeAdviceMethod(pjp, jpm, null, null);
}
AbstractAspectJAdvice.java
protected JoinPointMatch getJoinPointMatch() {
	//从当前线程中获取ReflectiveMethodInvocation方法调用
    MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    return getJoinPointMatch((ProxyMethodInvocation) mi);
}
protected JoinPointMatch getJoinPointMatch(ProxyMethodInvocation pmi) {
	//以切点表达式为 key,从当前ReflectiveMethodInvocation获取JoinPointMatch
    return (JoinPointMatch) pmi.getUserAttribute(this.pointcut.getExpression());
}
AspectJTest.java
@Around("test()")
public Object aroundTest(ProceedingJoinPoint p) {
    System.out.println("around before1");
    Object o = null;
    try {
        o = p.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    System.out.println("around after1");
    return o;
}
MethodInvocationProceedingJoinPoint.java
public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}
MethodBeforeAdviceInterceptor.java
public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
    return mi.proceed();
}
AspectJMethodBeforeAdvice.java
public void before(Method method, Object[] args, Object target) throws Throwable {
    invokeAdviceMethod(getJoinPointMatch(), null, null);
}
CglibAopProxy.java
protected Object invokeJoinpoint() throws Throwable {
    if (this.publicMethod) {
	    //如果是 public 类型
        return this.methodProxy.invoke(this.target, this.arguments);
    }
    else {
    	//非public 类型,设置method.setAccessible(true);
        return super.invokeJoinpoint();
    }
}

ReflectiveMethodInvocation.java
protected Object invokeJoinpoint() throws Throwable {
    return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
        throws Throwable {

    try {
    	//反射调用目标方法
        ReflectionUtils.makeAccessible(method);
        return method.invoke(target, args);
    }
    catch (InvocationTargetException ex) {
        throw ex.getTargetException();
    }
    catch (IllegalArgumentException ex) {
        throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
                method + "] on target [" + target + "]", ex);
    }
    catch (IllegalAccessException ex) {
        throw new AopInvocationException("Could not access method [" + method + "]", ex);
    }
}

AbstractAspectJAdvice.java
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
	//先进行参数绑定,再反射调用切点方法
    return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

protected Object invokeAdviceMethod(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable t)
        throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        //反射调用切点方法
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    }
    catch (IllegalArgumentException ex) {
        throw new AopInvocationException("Mismatch on arguments to advice method [" +
                this.aspectJAdviceMethod + "]; pointcut expression [" +
                this.pointcut.getPointcutExpression() + "]", ex);
    }
    catch (InvocationTargetException ex) {
        throw ex.getTargetException();
    }
}



protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) {
    calculateArgumentBindings();
    Object[] adviceInvocationArgs = new Object[this.adviceInvocationArgumentCount];
    int numBound = 0;
	//如果方法的第一个参数类型是JoinPoint或ProceedingJoinPoint,初始化JoinPoint或ProceedingJoinPoint值
    if (this.joinPointArgumentIndex != -1) {
        adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
        numBound++;
    }
    else if (this.joinPointStaticPartArgumentIndex != -1) {
    	//如果方法的第一个参数是JoinPoint.StaticPart值,初始化JoinPoint.StaticPart值
        adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
        numBound++;
    }

    if (!CollectionUtils.isEmpty(this.argumentBindings)) {
        if (jpMatch != null) {
            PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
            for (PointcutParameter parameter : parameterBindings) {
                String name = parameter.getName();
                Integer index = this.argumentBindings.get(name);
                //绑定普通参数值
                adviceInvocationArgs[index] = parameter.getBinding();
                numBound++;
            }
        }
        
        if (this.returningName != null) {
            Integer index = this.argumentBindings.get(this.returningName);
            //绑定返回值
            adviceInvocationArgs[index] = returnValue;
            numBound++;
        }
        
        if (this.throwingName != null) {
            Integer index = this.argumentBindings.get(this.throwingName);
             //绑定异常类型
            adviceInvocationArgs[index] = ex;
            numBound++;
        }
    }
    //如果己经绑定的参数个数和需要绑定的参数个数不相等,抛出异常
    if (numBound != this.adviceInvocationArgumentCount) {
        throw new IllegalStateException("Required to bind " + this.adviceInvocationArgumentCount
                + " arguments, but only bound " + numBound + " (JoinPointMatch " +
                (jpMatch == null ? "was NOT" : "WAS") +
                " bound in invocation)");
    }
    return adviceInvocationArgs;
}

public synchronized final void calculateArgumentBindings() {
    //如果参数个数为0或者己经绑定过了 ,则不需要绑定
    if (this.argumentsIntrospected || this.adviceInvocationArgumentCount == 0) {
        return;
    }

    int numUnboundArgs = this.adviceInvocationArgumentCount;
    Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
    //如果第一个参数是JoinPoint或ProceedingJoinPoint类型,需要绑定的参数个数--
    if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {
        numUnboundArgs--;
    }
    //如果方法参数是JoinPoint.StaticPart类型,需要绑定的参数--
    else if (maybeBindJoinPointStaticPart(parameterTypes[0])) {
        numUnboundArgs--;
    }
	//通过上面的判断,我们知道JoinPoint.StaticPart,JoinPoint,ProceedingJoinPoint必需作为切点方法第一个参数
    if (numUnboundArgs > 0) {	
    	//如果还有未绑定的参数,开始参数绑定
        bindArgumentsByName(numUnboundArgs);
    }

    this.argumentsIntrospected = true;
}

private void bindArgumentsByName(int numArgumentsExpectingToBind) {
    if (this.argumentNames == null) {
    	//先通过反射获取方法名,如果获取不到,再通过 ASM 技术从类字节码中获取方法参数名
        this.argumentNames = createParameterNameDiscoverer().getParameterNames(this.aspectJAdviceMethod);
    }
    if (this.argumentNames != null) {
    	//如果参数名不为空,开始绑定
        bindExplicitArguments(numArgumentsExpectingToBind);
    }
    //如果方法参数名为空,抛出异常
    else {
        throw new IllegalStateException("Advice method [" + this.aspectJAdviceMethod.getName() + "] " +
                "requires " + numArgumentsExpectingToBind + " arguments to be bound by name, but " +
                "the argument names were not specified and could not be discovered.");
    }
}
private void bindExplicitArguments(int numArgumentsLeftToBind) {
    this.argumentBindings = new HashMap<String, Integer>();
    //获取参数类型个数
    int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterTypes().length;
    //如果方法的参数名和参数类型个数不相等,抛出异常
    if (this.argumentNames.length != numExpectedArgumentNames) {
        throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames
                + " arguments to bind by name in advice, but actually found " +
                this.argumentNames.length + " arguments.");
    }

    //如果切点方法有JoinPoint或ProceedingJoinPoint或JoinPoint.StaticPart类型的参数,略过
    int argumentIndexOffset = this.adviceInvocationArgumentCount - numArgumentsLeftToBind;
    for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
    	//参数逐个绑定
        this.argumentBindings.put(this.argumentNames[i], i);
    }

    //returning参数绑定
    if (this.returningName != null) {
    	//@AfterReturning(value = "test(x,y)",returning = "returnValue")
    	//如果绑定的参数名中没有切点表达式中配置的returning,也就是方法参数名中没有returnValue,抛出异常
        if (!this.argumentBindings.containsKey(this.returningName)) {
            throw new IllegalStateException("Returning argument name '"
                    + this.returningName + "' was not bound in advice arguments");
        }
        else {
            Integer index = this.argumentBindings.get(this.returningName);
            //初始化方法返回值类型
            this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
             //初始化方法泛型返回值类型
            this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
        }
    }
    if (this.throwingName != null) {
    	// 如配置 @AfterThrowing(pointcut = "test(x,y)", throwing = "e") 
    	// 绑定参数名中没有 e ,抛出异常
        if (!this.argumentBindings.containsKey(this.throwingName)) {
            throw new IllegalStateException("Throwing argument name '"
                    + this.throwingName + "' was not bound in advice arguments");
        }
        else {
            Integer index = this.argumentBindings.get(this.throwingName);
            //初始化异常类型
            this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
        }
    }
	//配置切点参数
    configurePointcutParameters(argumentIndexOffset);
}


private void configurePointcutParameters(int argumentIndexOffset) {
    int numParametersToRemove = argumentIndexOffset;
    //去除掉方法参数中的 returning 和 throwing 所配置的参数
    if (this.returningName != null) {
        numParametersToRemove++;
    }
    if (this.throwingName != null) {
        numParametersToRemove++;
    }
    String[] pointcutParameterNames = new String[this.argumentNames.length - numParametersToRemove];
    Class<?>[] pointcutParameterTypes = new Class<?>[pointcutParameterNames.length];
    Class<?>[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();

    int index = 0;
    for (int i = 0; i < this.argumentNames.length; i++) {
        if (i < argumentIndexOffset) {
            continue;
        }
        //过虑掉returningName和throwingName 
        if (this.argumentNames[i].equals(this.returningName) ||
            this.argumentNames[i].equals(this.throwingName)) {
            continue;
        }
        pointcutParameterNames[index] = this.argumentNames[i];
        pointcutParameterTypes[index] = methodParameterTypes[i];
        index++;
    }
    //设置方法参数名和方法参数类型
    this.pointcut.setParameterNames(pointcutParameterNames);
    this.pointcut.setParameterTypes(pointcutParameterTypes);
}

CglibAopProxy.java
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
    //如果是这种情况
    // public AserviceImpl b(String x, User y) {
    //   System.out.println("print x=" + x + ",y=" + y);
    //   return this;
    // }
    //如果方法返回的是 this,但是目标方法并不是RawTargetAccess子孙类,则用当前代理替换掉方法返回值
    if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
        retVal = proxy;
    }
    Class<?> returnType = method.getReturnType();
    //如果返回值类型为空,但是方法的返回值不是 void 类型,是基本类型,int ,douible 等,将抛出异常
    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;
}

如果前面的篇博客都己经理解的小伙伴,再来看这一篇博客,有一种水到渠成感觉,虽然上面的代码看上去,感觉自己被绕晕了,但是还是有章法可寻的,因此,我们来看看,方法的调用流程。

流程:
{//调用ExposeInvocationInterceptor拦截器
public Object invoke(MethodInvocation mi) throws Throwable 
	return {//调用AspectJAfterThrowingAdvicer拦截器
   		try 
			{//调用AfterReturningAdviceInterceptor拦截器
				Object retVal = {//调用AspectJAfterAdvicer拦截器
					try 
						return {//调用AspectJAroundAdvice拦截器
							ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
							ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
							JoinPointMatch jpm = getJoinPointMatch(pmi);
							return {//调用AspectJTest的aroundTest方法
								System.out.println("around before1");
						        Object o = {//调用MethodBeforeAdviceInterceptor拦截器,调用AspectJTest.aroundTest()方法
						            	this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );//调用AspectJTest.abeforeTest()方法
										return {//调用AserviceImpl.b()方法
											invokeJoinpoint()
										}
						            }
						        System.out.println("around after1");
							}
						}
					finally 
						invokeAdviceMethod(getJoinPointMatch(), null, null);//调用AspectJTest.bafterTest()方法
				}
				//调用AspectJTest.AfterReturning()方法
				this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
				return retVal;
			}
		catch (Throwable t) 
			invokeAdviceMethod(getJoinPointMatch(), null, t);//调用AspectJTest.afterThrowing()方法
	}
}

上面的这个流程先申明一下{} 表示代码块,我用不同颜色代码块将拦截器链中的proceed()方法给替换掉,对于配置了@After,@AfterReturning,@AfterThrowing注解生成的拦截器,配置了@AfterThrowing切点拦截器调用在前,@After注解切点拦截器调用在后,而在拦截器中,proceed()方法调用在切点方法执行之前,因此就变成了,由@After,@AfterReturning,@AfterThrowing注解生成的拦截器越在前调用,反而切点方法越在后执行,而对于配置了@Before注解和@Around注解生成的拦截器,切点方法在proceed()方法执行之前,因此,拦截器越在前调用,切点方法就越先执行。

结语: 方法的调用看起来非常繁琐,各种递归调用,但是理解了调用顺序后,你会觉得 Spring 代码设计非常巧妙,在调用过程中,你没有看到调用链排序,而实现结果却有条不紊的调用着,Spring源码的巧妙,我也不在这里吹了,直接来总结一下吧。
我写了一大堆代码调用,其实 Spring 只做了三件事情 。

  1. 拦截器调用前再次匹配,匹配成功,方法参数封装,匹配失败,跳过该拦截器。
  2. 方法递归调用,这里需要注意一点的就是,在不断递归调用 proceed()方法时,before() ,around()切点方法是在 proceed()方法之前调用,after(),afterReturning(),afterThrowing()切点方法在 proceed()方法之后调用。
  3. 收尾工作,如果返回值是 this,则用代理对象替换返回值,如果返回值为空,而方法方法值写的是基本类型,抛出异常。

我这篇博客主要分析是 cglib 代理,如果是 jdk动态代理,是如何实现的呢?

思考?

还是同样的例子,Spring 是如何调用拦截器链的呢?

Aservice.java
public interface Aservice  {
    void b (String x,String y);
}
AserviceImpl.java
@Service
public class AserviceImpl implements Aservice {
    @Override
    public void b(String x,String y ) {
        System.out.println("print x=" + x + ",y="+y);
    }
}
AspectJTest.java
@Aspect
public class AspectJTest {

    @Pointcut("execution(* com.spring_1_100.test_61_70.test65.*.*(..)) && args(..)")
    public void test() {

    }

    @Before("test()")
    public void abeforeTest(JoinPoint jp) {
        System.out.println("abeforeTest" + JSON.toJSONString(jp.getArgs()));
    }


    @Before("test()")
    public void beforeTest() {
        System.out.println("beforeTest");
    }


    @After("test()")
    public void afterTest() {
        System.out.println("afterTest()");
    }


    @After("test()")
    public void bafterTest() {
        System.out.println("bafterTest()");
    }


    @AfterReturning("test()")
    public void AfterReturning() {
        System.out.println("AfterReturning()");
    }

    @AfterThrowing(pointcut = "test()", throwing = "e")
    public void afterThrowing(Exception e) {
        System.out.println("例外通知");
        System.out.println(e.getMessage());
    }

    @Around("test()")
    public Object aroundTest(ProceedingJoinPoint p) {
        System.out.println("around before1");
        Object o = null;
        try {
            o = p.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around after1");
        return o;
    }

}

spring65.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


    <aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
    <context:annotation-config></context:annotation-config>
    <context:component-scan base-package="com.spring_1_100.test_61_70.test65"></context:component-scan>

    <bean id="aservice" class="com.spring_1_100.test_61_70.test65.AserviceImpl"></bean>
    <bean class="com.spring_1_100.test_61_70.test65.AspectJTest"></bean>

</beans>

本文的github地址是
https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_1_100/test_61_70/test65_1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值