Spring系列之AOP分析之对目标对象的拦截过程(八)

简介:

我们在上一篇文章中简单的说了调用动态代理对象方法的过程,也说了AOP拦截器执行链的生成过程。我们接着说AOP对目标对象的拦截过程。下面的代码是我们要分析的重点:

//proxy:生成的动态代理对象
//target:目标对象
//method:目标方法
//args:目标方法参数
//targetClass:目标类对象
//chain: AOP拦截器执行链  是一个MethodInterceptor的集合 这个链条的获取过程参考我们上一篇文章的内容
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//开始执行AOP的拦截过程
retVal = invocation.proceed();

//构造ReflectiveMethodInvocation对象
protected ReflectiveMethodInvocation(
            Object proxy, Object target, Method method, Object[] arguments,
            Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

        this.proxy = proxy;
        this.target = target;
        this.targetClass = targetClass;
        //桥接方法
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        //转换参数
        this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }
    public Object proceed() throws Throwable {
        //    currentInterceptorIndex初始值为 -1 
        // 如果执行到链条的末尾 则直接调用连接点方法 即 直接调用目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            //下面会分析
            return invokeJoinpoint();
        }
        //获取集合中的 MethodInterceptor
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        //如果是InterceptorAndDynamicMethodMatcher类型
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            //这里每一次都去匹配是否适用于这个目标方法
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                //如果匹配则直接调用 MethodInterceptor的invoke方法
                //注意这里传入的参数是this 我们下面看一下 ReflectiveMethodInvocation的类型
                return dm.interceptor.invoke(this);
            }
            else {
                //如果不适用于此目标方法  则继续执行下一个链条 
                //递归调用
                return proceed();
            }
        }
        else {
            //说明是适用于此目标方法的 直接调用 MethodInterceptor的invoke方法  传入this即ReflectiveMethodInvocation实例
            //传入this进入 这样就可以形成一个调用的链条了
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

invokeJoinpoint方法

    protected Object invokeJoinpoint() throws Throwable {
        //this.target 目标对象
        //this.method 目标方法
        this.arguments 目标方法参数信息
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
            throws Throwable {

        // Use reflection to invoke the method.
        try {
            //设置方法可见性
            ReflectionUtils.makeAccessible(method);
            //反射调用  最终是通过反射去调用目标方法
            return method.invoke(target, args);
        }
        catch (InvocationTargetException ex) {
            // Invoked method threw a checked exception.
            // We must rethrow it. The client won't see the interceptor.
            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);
        }
    }

ReflectiveMethodInvocation的UML类图如下:
ReflectiveMethodInvocation
MethodInterceptorChain
MethodInterceptorChain
OK,我们在proceed()这个方法中看到了AOP对于目标方法的一个拦截的过程,其中很重要的一个点是调用MethodInterceptor的invoke方法。我们先看一下MethodInterceptor的主要UML类图(由于我们在开发中使用AspectJ注解的方式越来越多,所以我们这里说的基本上都是基于AspectJ注解的):
MethodInterceptor
从上图我们也可以看到不同的通知其实相当于不同的MethodInterceptor类型。像前置通知会交给:MethodBeforeAdviceInterceptor来进行处理,后置通知是由AspectJAfterAdvice来处理的,环绕通知是由AspectJAroundAdvice来处理的。我们也挑几个通知类型来说一下具体的调用过程。先说一下前置通知:
MethodBeforeAdviceInterceptor

//实现了MethodInterceptor接口
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
    //这个对象的获取参考这个方法org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
    //在之前的文章中有说过 不再描述
    //这个MethodBeforeAdvice是AspectJMethodBeforeAdvice实例
    private MethodBeforeAdvice advice;
    
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }
    
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        //这里就会执行  前置通知的逻辑 这里的advice是 AspectJMethodBeforeAdvice
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        //这里传入的MethodInvocation是ReflectiveMethodInvocation对象,即前面说的  传入this
        //相当于ReflectiveMethodInvocation.proceed() 递归调用。
        return mi.proceed();
    }
}

AspectJMethodBeforeAdvice#before代码如下:

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        //这里传进来的目标对象、目标参数、目标方法都没有用到
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }
    protected JoinPointMatch getJoinPointMatch() {
        //这里从线程上下文中获取MethodInvocation 看到这里你也许会感到奇怪  跟着文章分析来看 我们没有在设置过上下文的值啊
        //这里是怎么获取到MethodInvocation 的对象的呢?
        //不知道你是否还记得 我们在获取Advisor的时候 调用过这样的一个方法org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
        //在这个方法中会有这样的一段代码 
        // if (foundAspectJAdvice && //!advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
        //     如果获取到了 Advisor  则向 Advisor集合中添加第一个元素 即 ExposeInvocationInterceptor.ADVISOR
        //也就是说 我们的 Advisor列表中的第一个元素为ExposeInvocationInterceptor.ADVISOR 它是一个DefaultPointcutAdvisor的实例
        // 对于任何的目标方法都返回true  它的Advice是ExposeInvocationInterceptor
        //        advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
        //        return true;
        //    }
        // 这样我们就不难理解了,在调用ReflectiveMethodInvocation#proceed的时候第一个调用的MethodInterceptor是ExposeInvocationInterceptor
        //ExposeInvocationInterceptor的invoke方法的内容如下:
        //    public Object invoke(MethodInvocation mi) throws Throwable {
        //   先取出旧的MethodInvocation的值
        //    MethodInvocation oldInvocation = invocation.get();
        //    这里设置新的 MethodInvocation 就是这里了!!!
        //    invocation.set(mi);
        //    try {
        //      递归调用
        //        return mi.proceed();
        ///   }
        //   finally {
        //       invocation.set(oldInvocation);
        //   }
    //      }
        MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        //这里主要是获取 JoinPointMatch
        return getJoinPointMatch((ProxyMethodInvocation) mi);
    }

关于invokeAdviceMethod方法的内容我们在下一篇文章中继续分析

相关文章
|
28天前
|
设计模式 Java Maven
Spring Aop 底层责任链思路实现-springaopdi-ceng-ze-ren-lian-si-lu-shi-xian
Spring Aop 底层责任链思路实现-springaopdi-ceng-ze-ren-lian-si-lu-shi-xian
34 1
|
21天前
|
XML Java Maven
Spring之Aop的注解使用
Spring之Aop的注解使用
|
27天前
|
Java Spring
Spring 如何实现 AOP
Spring 如何实现 AOP
17 0
|
1月前
|
Java 编译器 程序员
Spring AOP 和 AspectJ 的比较
Spring AOP 和 AspectJ 的比较
37 0
|
5月前
|
Java 编译器 数据安全/隐私保护
自定义注解与AOP结合使用
自定义注解与AOP结合使用
59 0
|
6月前
|
Java 数据库连接 数据库
MyBatis与Spring集成&常用注解以及AOP和PageHelper分页插件整合
MyBatis与Spring集成&常用注解以及AOP和PageHelper分页插件整合
52 0
|
6月前
|
Java Spring
11Spring - 基于AspectJ的AOP开发(注解的方式)
11Spring - 基于AspectJ的AOP开发(注解的方式)
26 0
|
6月前
|
Java Spring
【注解】Spring AOP 面向切面编程之@Around的详细用法
【注解】Spring AOP 面向切面编程之@Around的详细用法
289 0
|
6月前
|
XML SQL Java
基于注解的AOP~
基于注解的AOP~
基于注解的AOP~
|
7月前
|
XML 监控 Java
注解IOC&AOP
扫描类下的注解,哪些包下的类需要使用IOC注解
65 0

热门文章

最新文章