交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
aop第7 章:Advisor与Advice
分享
未结
0
956
李延
LV6
2021-05-16
悬赏:20积分
# 作用 Advice 是 切面 我们在AspectJAdvisorFactory中看到根据不同的注解,创建处不同的子类。并在ReflectiveMethodInvocation中以链条的形式依次调研。 Advisor 是 切面的提供者。我们可以通过Advisor获取Advice。 # Advisor 实现 InstantiationModelAwarePointcutAdvisorImpl 在这个类中我们要关注, 1. getAdvice 获取切面 ## getAdvice ```java @Override public synchronized Advice getAdvice() { if (this.instantiatedAdvice == null) { this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); } return this.instantiatedAdvice; } private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) { Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName); return (advice != null ? advice : EMPTY_ADVICE); } ``` 我们看到最终调用的是AspectJAdvisorFactory 的getAdvice方法 # Advice 我们知道,在我们常用的切面中会有5种不同的注解,对应5种切面。下面逐一分析 ## AspectJAroundAdvice 环绕通知 ```java @Override @Nullable 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); return invokeAdviceMethod(pjp, jpm, null, null); } /** * Return the ProceedingJoinPoint for the current invocation, * instantiating it lazily if it hasn't been bound to the thread already. * @param rmi the current Spring AOP ReflectiveMethodInvocation, * which we'll use for attribute binding * @return the ProceedingJoinPoint to make available to advice methods */ protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) { return new MethodInvocationProceedingJoinPoint(rmi); } ``` 我们看到首先是准备参数。主要是ProceedingJoinPoint参数,通过ProxyMethodInvocation获取,其中ProxyMethodInvocation在5-2中已经说明。我们整个方法调用的链路就是通过它来进行的,包括方法的参数,method等信息。 并将其封装为ProceedingJoinPoint对象,在下一章节说明。 在最后调用invokeAdviceMethod方法,我们继续跟进。发现这个方法是父类的。 ```java // As above, but in this case we are given the join point. protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable t) throws Throwable { return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t)); } protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable { Object[] actualArgs = args; if (this.aspectJAdviceMethod.getParameterCount() == 0) { actualArgs = null; } try { ReflectionUtils.makeAccessible(this.aspectJAdviceMethod); // TODO AopUtils.invokeJoinpointUsingReflection 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(); } } ``` 首先通过argBinding 绑定参数。最后通过aspectJAdviceMethod类调用了切面方法,也就是我们业务代码里的内容。 我们下面查看参数的绑定 ```java protected Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex) { calculateArgumentBindings(); // AMC start Object[] adviceInvocationArgs = new Object[this.parameterTypes.length]; int numBound = 0; if (this.joinPointArgumentIndex != -1) { adviceInvocationArgs[this.joinPointArgumentIndex] = jp; numBound++; } else if (this.joinPointStaticPartArgumentIndex != -1) { adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart(); numBound++; } if (!CollectionUtils.isEmpty(this.argumentBindings)) { // binding from pointcut match 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++; } } // binding from returning clause if (this.returningName != null) { Integer index = this.argumentBindings.get(this.returningName); adviceInvocationArgs[index] = returnValue; numBound++; } // binding from thrown exception if (this.throwingName != null) { Integer index = this.argumentBindings.get(this.throwingName); adviceInvocationArgs[index] = ex; numBound++; } } if (numBound != this.parameterTypes.length) { throw new IllegalStateException("Required to bind " + this.parameterTypes.length + " arguments, but only bound " + numBound + " (JoinPointMatch " + (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)"); } return adviceInvocationArgs; } ``` //TODO 有点复杂,后面再解析吧 ## AspectJAfterAdvice 方法后通知 ```java @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } } ``` 我们看到方法的调用是写在finally里 ## AspectJMethodBeforeAdvice 方法前通知 ```java @Override public void before(Method method, Object[] args, @Nullable Object target) throws Throwable { invokeAdviceMethod(getJoinPointMatch(), null, null); } ``` 直接调用方法 ## AspectJAfterThrowingAdvice 异常通知 ```java @Override @Nullable public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } } ``` 在catch内调用
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号