Spring系列之AOP分析之获取Advice的过程(四)

简介:

我们在前面的文章中分析了从切面类中获取Advisor的过程,我们最后创建的Advisor实例为:InstantiationModelAwarePointcutAdvisorImpl,它是一个Advisor和PointcutAdvisor的实现类,所以我们可以从这个类中获取Advice和Pointcut。从之前的分析中我们也看到了Pointcut的赋值,在这一篇文章中我们将会具体分析Advice的创建过程。
我们在上一篇文章的末尾说到了这一段代码可以实例化Advice。我们来看看这个方法的代码:

this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
    //入参为切点表达式类
    //这里是通过调用aspectJAdvisorFactory来获取Advice
    //aspectJAdvisorFactory的实例是ReflectiveAspectJAdvisorFactory所以最终我们还是要到
    //ReflectiveAspectJAdvisorFactory中去分析Advice的获取过程
    //ReflectiveAspectJAdvisorFactory真是一个重要的类啊Advisor和Advice的获取都是在这个类中完成的
    //入参为:通知方法、切点表达式类、切面实例、切面的一个顺序、切面类名
    //倒腾了倒腾去基本上还是这几个参数
    return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
            this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    }

ReflectiveAspectJAdvisorFactory中getAdvice方法的代码如下

    public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
            MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
        //切面类 带有@Aspect注解的类
        Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        //验证切面类 不再分析了
        validate(candidateAspectClass);
        //又来一遍 根据通知方法 获取通知注解相关信息
        //在获取Advisor的方法 我们已经见过这个调用。这个在Spring的AnnotationUtils中会缓存方法的注解信息
        AspectJAnnotation<?> aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
            return null;
        }
        //再去校验一遍 如果不是切面类 则抛出异常
        if (!isAspect(candidateAspectClass)) {
            throw new AopConfigException("Advice must be declared inside an aspect type: " +
                    "Offending method '" + candidateAdviceMethod + "' in class [" +
                    candidateAspectClass.getName() + "]");
        }
        AbstractAspectJAdvice springAdvice;
        //在上一篇文章的分析中 我们说过在AspectJAnnotation中会存放通知类型
        switch (aspectJAnnotation.getAnnotationType()) {
            //如果是前置通知,则直接创建AspectJMethodBeforeAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtBefore:
                springAdvice = new AspectJMethodBeforeAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            //如果是后置通知,则直接创建AspectJAfterAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtAfter:
                springAdvice = new AspectJAfterAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            //如果是后置返回通知,则直接创建AspectJAfterReturningAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtAfterReturning:
                springAdvice = new AspectJAfterReturningAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                //设置后置返回值的参数name
                if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                    springAdvice.setReturningName(afterReturningAnnotation.returning());
                }
                break;
            //如果是后置异常通知,则直接创建AspectJAfterThrowingAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtAfterThrowing:
                springAdvice = new AspectJAfterThrowingAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                //设置后置异常通知 异常类型参数name
                if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                    springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                }
                break;
            //如果是后置异常通知,则直接创建AspectJAfterThrowingAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtAround:
                springAdvice = new AspectJAroundAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            //如果是切点方法,则什么也不做
            case AtPointcut:
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                }
                return null;
            //上面的那几种情况都不是的话,则抛出异常
            default:
                throw new UnsupportedOperationException(
                        "Unsupported advice type on method: " + candidateAdviceMethod);
        }

        // Now to configure the advice...
        //切面的名字
        springAdvice.setAspectName(aspectName);
        springAdvice.setDeclarationOrder(declarationOrder);
        //通知注解中的参数名
        String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
        if (argNames != null) {
            springAdvice.setArgumentNamesFromStringArray(argNames);
        }
        //参数绑定
        springAdvice.calculateArgumentBindings();
        return springAdvice;
    }

上面即是获取Advice的过程。我们简单的看一下calculateArgumentBindings这个方法做了什么事:
calculateArgumentBindings

    public synchronized final void calculateArgumentBindings() {
        //如果已经进行过参数绑定了  或者通知方法中没有参数
        if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
            return;
        }
        
        int numUnboundArgs = this.parameterTypes.length;
        //通知方法参数类型
        Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
        //如果第一个参数是JoinPoint或者ProceedingJoinPoint
        if (maybeBindJoinPoint(parameterTypes[0]) || 
        //这个方法中还有一个校验 即只有在环绕通知中第一个参数类型才能是ProceedingJoinPoint
        maybeBindProceedingJoinPoint(parameterTypes[0])) {
            numUnboundArgs--;
        }
        //如果第一个参数是JoinPoint.StaticPart
        else if (maybeBindJoinPointStaticPart(parameterTypes[0])) {
            numUnboundArgs--;
        }

        if (numUnboundArgs > 0) {
            //进行参数绑定 绑定过程略复杂
            //常见的场景是我们使用 后置返回通知和后置异常通知的时候 需要指定 returning和throwing的值 
            bindArgumentsByName(numUnboundArgs);
        }
        this.argumentsIntrospected = true;
    }

通过前面的分析我们可以了解到一个切面中的通知方法会生成一个Advisor实例(如InstantiationModelAwarePointcutAdvisorImpl,其实这个也是我们在SpringAOP中最常用的一个Advisor实现类),在生成这个Advisor实例的过程中会创建一个相应的Advice实例! 一个通知方法---->一个Advisor(包含Pointcut)------>一个Advice!
PS:这里只是一个生成Advice的地方,在其他的地方也会生成Advice,我们在以后再分析。

相关文章
|
22天前
|
XML Java 数据格式
Spring Core核心类库的功能与应用实践分析
【12月更文挑战第1天】大家好,今天我们来聊聊Spring Core这个强大的核心类库。Spring Core作为Spring框架的基础,提供了控制反转(IOC)和依赖注入(DI)等核心功能,以及企业级功能,如JNDI和定时任务等。通过本文,我们将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring Core,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
49 14
|
1月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
24天前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
51 5
|
29天前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
57 8
|
29天前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
29天前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
41 5
|
29天前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
42 4
|
2月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
50 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
1月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
37 1
|
1月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
42 0