1 利用

日志、事务、限流、统计、上下文切换、异步等非业务性能的逻辑解决都能够用

2 例子

网上随处可见,这里只是简略举个例子

@Aspect@Componentpublic class DemoAspect {    @Pointcut("execution(* com.example.demo2.controller.DemoController.sayDemo())")    public void aa(){        System.out.println("pointcut");    }    @Before("aa()")    public void beforeDemo(JoinPoint joinPoint){        System.out.println(joinPoint);        System.out.println("before demo");    }    @After("aa()")    public void afterDemo(){        System.out.println("after demo");    }    @Around("aa()")    public void zaroundDemo(ProceedingJoinPoint joinPoint){        System.out.println("demo around1  ");        try {            joinPoint.proceed();        } catch (Throwable throwable) {            throwable.printStackTrace();        }        System.out.println("demo around2");    }}

3 相干重要类

AbstractAspectJAdvise
AspectJAroundAdvice
AspectJMethodBeforeAdvice
AspectJAfterThrowingAdvice
AspectJAfterAdvice

AspectjAroundAdvice -- 继承自methodInterceptor

AspectjMethodBeforeAdvice --- 这还有一个MethodBeforeInterceptor 用来实现动静代理

4 调用过程

  1. 通过cglib代理生成代理类,外面重写父类的办法,退出拦截器DynamicCglibMethodInterceptor,这外面退出了对于这个类的所有织入告诉(advice)对应的拦截器,比方:AspectJMethodBeforeAdvice---MethodBeforeAdviceInterceptor;AspectJAroundAdvice的拦截器就是自身;
  2. 在进行调用的时候,会先遍历所有的Advice对应的拦截器,调用外面的invoke办法;把以后的CglibMethodInvocation对象传下去;(典型责任链模式)
    3.重点:AspectJAroundAdvise外面有一个ProceedingJoinPoint参数,这个是如何调用的呢? 实际上外面在Advice外面都是通过返回调用了切面类中的告诉办法,method.invoke(obj,args);为了实现盘绕告诉呢?在初始化MethodInvokcationProceedingJoinPoint的时候,就把CglibMethodInvocation也传入进去了,不便调用链的持续运行;如果是调用链最初一个,那么methodInvocationProceedingJoinPoint调用实现后,间接返回到盘绕告诉办法外面,而后持续向下执行,直至完结即可。

5 源码解析

5.1 动静代理类

依据

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,fileName);

生成的动静代理对象,能够看出,外面会有一个DemoController$$EnhanceByCglib这个对象,外面有一个callback[]数组,这个就是记录的所有拦截器;
通过动静生成的代理类调用demo办法的时候,实际上走的流程是:

public final void sayDemo() {        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;        if (var10000 == null) {            CGLIB$BIND_CALLBACKS(this);            var10000 = this.CGLIB$CALLBACK_0;        }# 如果有拦截器,则调用拦截器办法,        if (var10000 != null) {            var10000.intercept(this, CGLIB$sayDemo$0$Method, CGLIB$emptyArgs, CGLIB$sayDemo$0$Proxy);        } else {            super.sayDemo();        }    }

能够看到动静代理产生的类重写了父类的DemoController中的sayDemo办法,而后有写了一个办法叫

final void CGLIB$sayDemo$0() {        super.sayDemo();    }

来调用父类的办法;
重点看下拦截器是什么?怎么调用的?

5.2 DynamicAdvisedInterceptor

注入的拦截器,
在intercept办法中,会判断advice是否为空,如果不为空,则会调用

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

5.3 CglibMethodInvocation

调用父类proceed办法

public Object proceed() throws Throwable {        // We start with an index of -1 and increment early.// 如果是最初一个,那么就完事了。        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {            return invokeJoinpoint();        }// 依据index 找下一个advice是什么?        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;            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());            if (dm.methodMatcher.matches(this.method, 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.// 走到这里,调用advice对应的MethodInterceptor            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);        }    }

假如:第一个是盘绕告诉对应的拦截器

5.4 AspectJAroundAdvice

public Object invoke(MethodInvocation mi) throws Throwable {        if (!(mi instanceof ProxyMethodInvocation)) {            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);        }// 把以后的CglibMethodInvocation 实例对象传到ProceedingJoinPoint中,不便前面来用;        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;        ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);        JoinPointMatch jpm = getJoinPointMatch(pmi);// 利用反射调用切面中的盘绕告诉办法,(即上文的zaroundDemo办法)        return invokeAdviceMethod(pjp, jpm, null, null);    }

代码如下

 @Around("aa()")    public void zaroundDemo(ProceedingJoinPoint joinPoint){        System.out.println("demo around1  ");        try {// 这里就是调用MethodInvocationProceedingJoinPoint;            joinPoint.proceed();        } catch (Throwable throwable) {            throwable.printStackTrace();        }        System.out.println("demo around2");    }

MethodInvocationProceedingJoinPoint.proceed办法,能够发现,实际上它调用的是下面作为成员变量传进来的CglibMethodInvocation对象;造成一个调用链;

public Object proceed() throws Throwable {        return this.methodInvocation.invocableClone().proceed();    }

5.5 AspectJMethodBeforeAdvice--MethodBeforeAdviceInterceptor

拦截器外面的逻辑:

  1. 先调用前置告诉的before办法,
  2. 再返回调用链的CglibMethodInvocation--持续责任链的调用;
public Object invoke(MethodInvocation mi) throws Throwable {        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());        return mi.proceed();    }

AspectJMethodBeforeAdvice.proceed
也是利用反射进行调用切面中的前置告诉;

    @Override    public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {        invokeAdviceMethod(getJoinPointMatch(), null, null);    }

5.6 AspectJAfterAdvice

在finally外面在反射调用织入的后置告诉;

    public Object invoke(MethodInvocation mi) throws Throwable {        try {            return mi.proceed();        }        finally {            invokeAdviceMethod(getJoinPointMatch(), null, null);        }    }

5.7 责任链的最初一步:--invokeJoinpoint

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

invokeJoinPoint

protected Object invokeJoinpoint() throws Throwable { // 如果通过cglib代理,则调用动静代理办法            if (this.methodProxy != null) {                try {                    return this.methodProxy.invoke(this.target, this.arguments);                }                catch (CodeGenerationException ex) {                    logFastClassGenerationFailure(this.method);                }            }// 否则就通过反射调用            return super.invokeJoinpoint();        }

6 总结

  1. AOP 大量应用反射,诸如:调用织入告诉
  2. spring将所有的告诉放到一个list中,利用责任链模式进行逐个调用;
  3. 最初在触发cglib的动静代理,调用MethodProxy.invoke办法