个人随笔
目录
一个简单的例子来探寻SpringAOP执行源码的主脉络(二):执行代理方法
2021-08-14 17:53:02

通过第一篇文章我们已经知道了怎么生成代理对象,现在这篇文章我们来跟踪下源码怎么执行代理方法。一个简单的例子来探寻SpringAOP执行源码的主脉络(一):创建代理对象

我们调试可以发现,我们的代理对象内容如下

里面有两个Advisor,第一个应该是spring默认的,我们定义的增强器为

  1. InstantiationModelAwarePointcutAdvisor

这个也就对应我们的

  1. @Aspect
  2. @Component
  3. public class MyAspect {
  4. @Pointcut("execution(public * com.suibibk.spring.service.*.*(..))")
  5. public void web() {
  6. }
  7. @Around("web()")
  8. public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
  9. System.out.println("之前");
  10. Object obj =pjp.proceed();
  11. System.out.println("之后");
  12. return obj;
  13. }
  14. }

里面的doAround方法,是这个方法的包装。我们点击下一步,进入到这个代里对象的invoke方法

  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  2. Object oldProxy = null;
  3. boolean setProxyContext = false;
  4. TargetSource targetSource = this.advised.targetSource;
  5. Object target = null;
  6. try {
  7. if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
  8. // The target does not implement the equals(Object) method itself.
  9. return equals(args[0]);
  10. }
  11. else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
  12. // The target does not implement the hashCode() method itself.
  13. return hashCode();
  14. }
  15. else if (method.getDeclaringClass() == DecoratingProxy.class) {
  16. // There is only getDecoratedClass() declared -> dispatch to proxy config.
  17. return AopProxyUtils.ultimateTargetClass(this.advised);
  18. }
  19. else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
  20. method.getDeclaringClass().isAssignableFrom(Advised.class)) {
  21. // Service invocations on ProxyConfig with the proxy config...
  22. return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
  23. }
  24. Object retVal;
  25. //这个如果开启表明会将当前代理对象放到当前西线程中,然后你在当前方法中就可以获取当前的代理对象了。
  26. if (this.advised.exposeProxy) {
  27. // Make invocation available if necessary.
  28. oldProxy = AopContext.setCurrentProxy(proxy);
  29. setProxyContext = true;
  30. }
  31. // Get as late as possible to minimize the time we "own" the target,
  32. // in case it comes from a pool.
  33. target = targetSource.getTarget();
  34. Class<?> targetClass = (target != null ? target.getClass() : null);
  35. // Get the interception chain for this method.
  36. //这里就是获取两个增强器,第二个才是我们要的
  37. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  38. // Check whether we have any advice. If we don't, we can fallback on direct
  39. // reflective invocation of the target, and avoid creating a MethodInvocation.
  40. if (chain.isEmpty()) {
  41. // We can skip creating a MethodInvocation: just invoke the target directly
  42. // Note that the final invoker must be an InvokerInterceptor so we know it does
  43. // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
  44. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
  45. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
  46. }
  47. else {
  48. // We need to create a method invocation...
  49. //把全部信息都封装成一个MethodInvocation对象,然后调用proceed方法。
  50. MethodInvocation invocation =
  51. new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  52. // Proceed to the joinpoint through the interceptor chain.
  53. retVal = invocation.proceed();
  54. }
  55. // Massage return value if necessary.
  56. Class<?> returnType = method.getReturnType();
  57. if (retVal != null && retVal == target &&
  58. returnType != Object.class && returnType.isInstance(proxy) &&
  59. !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
  60. // Special case: it returned "this" and the return type of the method
  61. // is type-compatible. Note that we can't help if the target sets
  62. // a reference to itself in another returned object.
  63. retVal = proxy;
  64. }
  65. else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
  66. throw new AopInvocationException(
  67. "Null return value from advice does not match primitive return type for: " + method);
  68. }
  69. return retVal;
  70. }
  71. finally {
  72. if (target != null && !targetSource.isStatic()) {
  73. // Must have come from TargetSource.
  74. targetSource.releaseTarget(target);
  75. }
  76. if (setProxyContext) {
  77. // Restore old proxy.
  78. AopContext.setCurrentProxy(oldProxy);
  79. }
  80. }
  81. }

上面关键步骤都有中文注释,主要就是获取Advisor链,然后封装成一个MethodInvocation对象。我们调试进去。

  1. @Override
  2. @Nullable
  3. public Object proceed() throws Throwable {
  4. // We start with an index of -1 and increment early.
  5. //这里是递归的返回出口
  6. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
  7. return invokeJoinpoint();
  8. }
  9. //这里是获取当前的一个下标,也就是先加1,一开始是-1
  10. Object interceptorOrInterceptionAdvice =
  11. this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  12. if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
  13. // Evaluate dynamic method matcher here: static part will already have
  14. // been evaluated and found to match.
  15. InterceptorAndDynamicMethodMatcher dm =
  16. (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
  17. Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
  18. if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
  19. return dm.interceptor.invoke(this);
  20. }
  21. else {
  22. // Dynamic matching failed.
  23. // Skip this interceptor and invoke the next in the chain.
  24. return proceed();
  25. }
  26. }
  27. else {
  28. // It's an interceptor, so we just invoke it: The pointcut will have
  29. // been evaluated statically before this object was constructed.
  30. //这里把当前类对象传过去
  31. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  32. }
  33. }

这里通过用巧妙的方式,把循环去掉,变成递归。其实就是记录一个下标,没执行一个Advisor就自增一次,等所有Advisor都执行完了后,才会去调用正真的被代理对象的业务逻辑方法

  1. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
  2. return invokeJoinpoint();
  3. }

我们发现我们的Advisor不是InterceptorAndDynamicMethodMatcher,所以会进入后面的方法

  1. public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable
  1. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  1. @Override
  2. public Object invoke(MethodInvocation mi) throws Throwable {
  3. MethodInvocation oldInvocation = invocation.get();
  4. invocation.set(mi);
  5. try {
  6. return mi.proceed();
  7. }
  8. finally {
  9. invocation.set(oldInvocation);
  10. }
  11. }

这里执行完业务操作后又调用了

  1. return mi.proceed();

又回到了上面的方法,不过此时currentInterceptorIndex==0,所以自加后会取到第二个,第二个是我们的切面方法

  1. @Override
  2. public Object invoke(MethodInvocation mi) throws Throwable {
  3. if (!(mi instanceof ProxyMethodInvocation)) {
  4. throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
  5. }
  6. ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
  7. ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
  8. JoinPointMatch jpm = getJoinPointMatch(pmi);
  9. return invokeAdviceMethod(pjp, jpm, null, null);
  10. }

我们进到

  1. invokeAdviceMethod(pjp, jpm, null, null);

看看是怎么执行我们的

  1. @Around("web()")
  2. public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
  3. System.out.println("之前");
  4. Object obj =pjp.proceed();
  5. System.out.println("之后");
  6. return obj;
  7. }

方法的

  1. protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
  2. @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
  3. return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
  4. }

我们进入到

  1. invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
  1. protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
  2. Object[] actualArgs = args;
  3. if (this.aspectJAdviceMethod.getParameterCount() == 0) {
  4. actualArgs = null;
  5. }
  6. try {
  7. ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
  8. // TODO AopUtils.invokeJoinpointUsingReflection
  9. //应该是在这里执行的
  10. return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
  11. }
  12. catch (IllegalArgumentException ex) {
  13. throw new AopInvocationException("Mismatch on arguments to advice method [" +
  14. this.aspectJAdviceMethod + "]; pointcut expression [" +
  15. this.pointcut.getPointcutExpression() + "]", ex);
  16. }
  17. catch (InvocationTargetException ex) {
  18. throw ex.getTargetException();
  19. }
  20. });

aspectJAdviceMethod这个就是我们的doAround方法,这里是执行这个方法。这一个方法运行会跳到我们的

  1. @Around("web()")
  2. public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
  3. System.out.println("之前");
  4. Object obj =pjp.proceed();
  5. System.out.println("之后");
  6. return obj;
  7. }

执行第一条语句答应后会取执行我们的proceed()方法,这里会去执行我们的test()方法,然后又会跳到

  1. //这里是递归的返回出口
  2. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
  3. return invokeJoinpoint();
  4. }

这里的invokeJoinpoint()就是执行我们正真的方法

  1. @Nullable
  2. protected Object invokeJoinpoint() throws Throwable {
  3. return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
  4. }
  1. @Nullable
  2. public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
  3. throws Throwable {
  4. // Use reflection to invoke the method.
  5. try {
  6. ReflectionUtils.makeAccessible(method);
  7. //执行业务逻辑
  8. return method.invoke(target, args);
  9. }
  10. catch (InvocationTargetException ex) {
  11. // Invoked method threw a checked exception.
  12. // We must rethrow it. The client won't see the interceptor.
  13. throw ex.getTargetException();
  14. }
  15. catch (IllegalArgumentException ex) {
  16. throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
  17. method + "] on target [" + target + "]", ex);
  18. }
  19. catch (IllegalAccessException ex) {
  20. throw new AopInvocationException("Could not access method [" + method + "]", ex);
  21. }
  22. }

执行完业务逻辑后又会跳回

  1. @Around("web()")
  2. public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
  3. System.out.println("之前");
  4. Object obj =pjp.proceed();
  5. System.out.println("之后");
  6. return obj;
  7. }

打印”之后”然后返回。然后就执行完了,总体来说还是比较简单的。

总之:主要的业务处理考的是每个Advisor里面的advice(通知)的invoke方法。所以后面我们看事务的代理对象执行逻辑也只需要看它的advisor里面的advice的invoke方法就可以了。

 234

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2