前面五篇博客己经详细分析了注解如何解析,切面表达式如何解析,切面表达式如何与目标方法匹配,以及生成动态代理,今天,我们来分析一下,代理生成了,方法又是如何调用的呢?方法调用的顺序又是如何控制的呢?先看下面示例代码。
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 只做了三件事情 。
- 拦截器调用前再次匹配,匹配成功,方法参数封装,匹配失败,跳过该拦截器。
- 方法递归调用,这里需要注意一点的就是,在不断递归调用 proceed()方法时,before() ,around()切点方法是在 proceed()方法之前调用,after(),afterReturning(),afterThrowing()切点方法在 proceed()方法之后调用。
- 收尾工作,如果返回值是 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