关于切面的概念可以参考下这篇文章,已经解释的很好了: https://mp.weixin.qq.com/s/BYxXMAEIfOSCCx1KanP9lg
但是上面流于概念的讲解,少了一些具体源码上的分析。
下面按照我的理解,说明一下吧。
@Component public class MathCalculator { public int divile(int a, int b) { // step1 : copy refence // step2 : patse whithout format : com.wy.aop.MathCalculator#divile return a / b; } }
@Aspect @Component public class LogAspect { @Pointcut("execution(public int com.wy.aop.MathCalculator.divile(..))") public void pointCut() { } @Before("pointCut()") public void logStart(JoinPoint joinPoint) { System.out .println(joinPoint.getSignature() + " Before 除法运行:方法名:" + "参数表:" + Arrays.asList(joinPoint.getArgs())); } @After("com.wy.aop.LogAspect.pointCut()") public void logEnd(JoinPoint joinPoint) { System.out.println(joinPoint.getSignature() + "After 除法结束:"); } @AfterReturning(value = "pointCut()", returning = "result") public void logReturn(JoinPoint joinPoint, Object result) { System.out.println(joinPoint.getSignature() + "AfterReturning 除法返回:" + result); } @AfterThrowing(value = "pointCut()", throwing = "exception") public void logExp(JoinPoint joinPoint, Exception exception) { System.out.println(joinPoint.getSignature() + "AfterThrowing 除法异常:" + exception.getMessage()); } }
@EnableAspectJAutoProxy @ComponentScan(value = "com.wy.aop") @Configuration public class MainConfigOfAOP { }
具体可以分为三大步
参考另外一篇文章:六. 容器的创建流程
AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器。
具体实现类名 :org.springframework.aop.config.internalAutoProxyCreator
internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
finishBeanFactoryInitialization() 初始化剩下的单实例bean
3)、组件创建完之后,判断组件是否需要增强
是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
把切面的通知方法,包装成增强器(Advisor)
给业务逻辑组件创建一个代理对象(CglibAopProxy)
通过 CglibAopProxy.intercept( ) 拦截。
执行顺序:
具体的代码流程:下面再论述。
AOP 的核心理解:
@Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { }
通过这个注解,从 IOC 容器中定义一个组件 : org.springframework.aop.config.internalAutoProxyCreator
具体的 bean 是 : AnnotationAwareAspectJAutoProxyCreator
先看看他的实现继承结构
主要关注: 它实现了 BeanPostProcessor (在bean初始化完成前后做事情)、自动装配BeanFactory (Aware)
此节请结合 六、容器的创建流程
关键源码如下 :
if (this.advisedBeans.containsKey(cacheKey)) { return null; } if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; }
这里主要关心 业务类(MathCalculator) 和 切面类(LogAspect)
大致步骤如下:
1、判断当前 bean 是否在 advisedBeans 中(保存了所有需要增强bean)
2、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,
或者是否是切面(@Aspect)
3、是否需要跳过
如果包含 则直接 ruturn
如果都不包含,则进入后续,做一些简单的处理
把所有的切面对应的增强信息 包装成了 Advisor
InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public void com.wy.aop.LogAspect.logStart(org.aspectj.lang.JoinPoint)]; perClauseKind=SINGLETON
增强器是 : InstantiationModelAwarePointcutAdvisor
所以 postProcessBeforeInstantiation 主要做一些前置工作。
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
主要步骤: wrapIfNecessary
总结:经过这一步骤。如果这个bean 有canApply 的Adivse 。就会得到一个增强类的代理对象 CglibAopProxy
return wrapIfNecessary(bean, beanName, cacheKey); // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
返回的 specificInterceptors 数组
具体的可以 debug 看下源码
this.advisedBeans.put(cacheKey, Boolean.TRUE);
标识当前 bean 已经被增强过
Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
给容器中返回当前组件使用cglib增强了的代理对象;
之后,容器中获得到的就是这个组件(bean:MathCalculator)的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;也就是切面的执行流程
所以保护 Advice 的 bean 的生命周期是:
在调用目标方法的时候 :
MathCalculator mathCalculator = ctx.getBean(MathCalculator.class); // new MathCalculator() 不会起作用 因为没有使用容器 spring容器管理的 int divile = mathCalculator.divile(4, 2);
此时的目标方法 是 : CglibAopProxy 增强后的代理对象。 里面包括 五个增强器(Advice)
保存了通知方法的信息。
通过 CglibAopProxy.intercept() 拦截目标方法的执行
首先获取 Interception 链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // We can skip creating a MethodInvocation: just invoke the target directly. // Note that the final invoker must be an InvokerInterceptor, so we know // it does nothing but a reflective operation on the target, and no hot // swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // We need to create a method invocation... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); }
拦截器链。 就是多个 intercept 组成的链式结构
核心 是1. 如何获取的拦截器连
2.拦截器链是如何工作的
源码类 : org/springframework/aop/framework/DefaultAdvisorChainFactory.java
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
遍历所有的增强器转换为 MethodInterceptor
获得 list 就是拦截器链 chain
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
最终目的 : 获取CglibMethodInvocation,调用 proceed() 方法
就是触发拦截器链的触发过程。
执行 实现类的方法
int divile = mathCalculator.divile(4, 2);
源码如下:
@Override @Nullable public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }
拦截器链的触发过程;
2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
拦截器链的机制,保证通知方法与目标方法的执行顺序;
为了减少企业,先看一下调用的流程图
这个设计的也太经典了
对应的调用链:
执行代码:
还没有执行方法前。 依次调用所有的Aspect 的拦截器
执行最后一个前置的时候
@Override public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); }
然后执行目标方法 : invokeJoinpoint()
然后执行
try { return mi.proceed(); } finally { // 返回上一次方法 // 每一个上级方法 Advise 都有自己单独做的事情 invokeAdviceMethod(getJoinPointMatch(), null, null); }
每一个拦截器等待下一个拦截器 执行完之后 返回在执行
依次是
@Override public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }
如果抛出异常:
try { return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; }
拦截器链。 保证了通知方法和目标方法的顺序, before invoke return 的顺序