【一】Spring AOP 最全源码详解之AOP元数据解析

目录java

1.  findCandidateAdvisorsspring

2. buildAspectJAdvisorsexpress

2.1. 建立一个MetadataAwareAspectInstanceFactory对象数组

2.2. getAdvisors(factory)缓存

2.3 getAdviceapp

3. 附录:本工程项目文件框架


bean建立过程当中,在createBean步骤的resolveBeforeInstantiation中会调用beanPostProcessor处理器执行各自的postProcessBeforeInstantiation方法。在Spring在引入了AOP的状况下,后置处理器会多出一个AnnotationAwareAspectJAutoProxyCreator。在建立bean进行到该步骤的时候,该beanPostProcessor会在postProcessBeforeInstantiation方法中进行代理类Pointcut,JointPoint,Advice,Advisor的解析和缓存。为后续初始化bean中实现bean的代理作好准备。post

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

直接来看调用ibp.postProcessBeforeInstantiation(beanClass, beanName)的实现方法, ui

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // 若是是普通bean,则返回beanName,若是是FactoryBean,则返回加上前缀&的&beanName
    Object cacheKey = getCacheKey(beanClass, beanName);

    // 第一次进入时,targetSourcedBeans还未缓存有对象,故会进入。
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        // 若是this.advisedBeans有缓存值,说明该bean已经被解析过了,直接返回null就跳过了后续的解析
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // 基础类不该该被代理
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }
    // 若是用户自定义了TargetSource,那么直接返回用户自定义的代理类。不然返回null,使得Spring框架能继续执行下去。
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    return null;
}

首先getCacheKey是获取beanName,若是是FactoryBean,那么beanName是要加上前缀"&"。第一次进入时,if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName))确定是会进入的。若是advisedBeans有缓存值,说明该bean已经被解析过了,直接返回null就跳过了后续的解析,不然进入第二个if分支。第一个条件isInfrastructureClass()是判断当前bean类型是不是基础类型,若是是则不会被代理。基础类型有Advice.class,Pointcut.class, Advisor.class, AopInfrastructureBean.class这4种。关键的核心代码是在shouldSkip(beanClass, beanName)中,返回的结果用于判断是否要跳过解析。可是执行的过程却远远不是一句话能说明白的,咱们一块儿深刻剖析shouldSkip方法。(后续的getCustomTargetSource方法是返回用户自定义的代理类。若是没有定义就返回null,使得Spring框架能继续执行下去。这里后续再也不分析~)this

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // findCandidateAdvisors最终会由BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans执行
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 找到的candidate中有beanName与AspectJPointcutAdvisor相同,也就是PointcutAdvisor的实现类,则不会进行做为代理的尝试。
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor &&
                ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
            return true;
        }
    }
    // 根据ORIGINAL_INSTANCE_SUFFIX判断给定bean名称是“原始实例”类型,若是是就跳过代理的尝试。
    return super.shouldSkip(beanClass, beanName);
}

核心的步骤是findCandidateAdvisors,用于寻找和解析advisor。而后再找到的advisor们中判断是否能够跳过。有两种状况能够被跳过:1.AspectName恰好就是这个bean的name;2.这个bean是原始实例,原始bean的后缀有“.ORIGINAL”标志。

接下来咱们进入核心的findCandidateAdvisors方法分析:

protected List<Advisor> findCandidateAdvisors() {
    List<Advisor> advisors = super.findCandidateAdvisors();
    // 合并全局的advisors后返回
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

1.  findCandidateAdvisors

super.findCandidateAdvisors()会借助BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans执行,咱们直接来看findAdvisorBeans。

public List<Advisor> findAdvisorBeans() {
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
        // 从bean工厂中寻找Advisor.class,而且是单例类型的beanName
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                // 若是正在建立就跳过
            }
            else {
                try {
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    if (rootCause instanceof BeanCurrentlyInCreationException) {
                        BeanCreationException bce = (BeanCreationException) rootCause;
                        String bceBeanName = bce.getBeanName();
                        if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {                            
                            continue;
                        }
                    }
                    throw ex;
                }
            }
        }
    }
    return advisors;
}

首先尝试从拿到缓存的advisors,若是没有缓存,那么就从bean工厂中尝试找出从bean工厂中寻找继承了Advisor.class接口的类,并过滤出单例类型的beanName返回。·若是项目中没有继承接口Advisor的bean,那么直接返回new一个了ArrayList返回。若是有继承Advisor接口的bean,那么就从bean工厂中实例化出来添加到advisors list中返回上层执行后续的代码。

2. buildAspectJAdvisors

下面咱们来看this.aspectJAdvisorsBuilder.buildAspectJAdvisors()的执行流程。

public List<Advisor> buildAspectJAdvisors() {
	//  仍是先从缓存中获取,第一次进来确定是为null
    List<String> aspectNames = this.aspectBeanNames;

    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();
                // 从bean工厂中拿出全部beanName
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                for (String beanName : beanNames) {
                    // 判断这个bean是否能够作自动代理的可能
                    // 具体的判断依据是根据org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#includePatterns中
                    // 添加的规则进行过滤。默认是没有添加任何规则,也就是任何bean都有被代理的可能。
                    if (!isEligibleBean(beanName)) {
                        continue;
                    }

                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
                    // 看看这个bean的类中是否有Aspect的注解,若是
                    // 好比OperationAop类中就含有这样的注解。第一次解析出注解后,会将其添加到AnnotationUtils的findAnnotationCache map中缓存
                    if (this.advisorFactory.isAspect(beanType)) {
                        // 先添加到临时list中,后边会追加到this.aspectBeanNames中。
                        aspectNames.add(beanName);
                        // 这里其实就是看这个bean是不是单例的。若是是单例的,那么它的代理bean也会是单例的,不然就看成是原型的。
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        // aspect (perthis/target/cflow/cflowbelow)有这几种使用模式,我一个都没用过>.<!。 默认是SINGLETON
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            // 建立一个针对当前类型的一个单例的代理工厂
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // 解析和建立对应代理工厂的advisor
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            // 放入BeanFactoryAspectJAdvisorsBuilder的缓存map advisorsCache中
                            if (this.beanFactory.isSingleton(beanName)) {
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            else {
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        }
                        else {
                            MetadataAwareAspectInstanceFactory factory =
                                    new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                            this.aspectFactoryCache.put(beanName, factory);
                            advisors.addAll(this.advisorFactory.getAdvisors(factory));
                        }
                    }
                }
                this.aspectBeanNames = aspectNames;
                return advisors;
            }
        }
    }
    if (aspectNames.isEmpty()) {
        return Collections.emptyList();
    }
    List<Advisor> advisors = new ArrayList<>();
    for (String aspectName : aspectNames) {
        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
        if (cachedAdvisors != null) {
            advisors.addAll(cachedAdvisors);
        }
        else {
            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
        }
    }
    return advisors;
}

进来首先仍是先从缓存中获取,第一次进来确定是为null。DCL检查this.aspectBeanNames是否已经有缓存。检查都经过之后,首先从bean工厂中拿出全部到beanNames中,而后遍历这些beanNames进行aop的相关解析。isEligibleBean(beanName)是判断这个bean是否能够作自动代理的可能,具体的判断依据是根据AnnotationAwareAspectJAutoProxyCreator#includePatterns中添加的规则进行过滤。默认是没有添加任何规则,也就是任何bean都有被代理的可能。advisorFactory.isAspect(beanType)是判断这个bean的类中是否有Aspect的注解,好比OperationAop.class类中就含有这样的注解。第一次解析出注解后,会将其添加到AnnotationUtils的findAnnotationCache map中缓存。随后根据PerClauseKind.SINGLETON分开处理单例与原型的advisorFactory。aspect (perthis/target/cflow/cflowbelow)有这几种使用模式,默认是SINGLETON。咱们只分析单例的状况,原型的大同小异留给读者自行分析吧。重点来看这三行代码:

//建立一个针对当前类型的一个单例的代理工厂
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 解析和建立对应代理工厂的advisor
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 放入BeanFactoryAspectJAdvisorsBuilder的缓存map advisorsCache中
if (this.beanFactory.isSingleton(beanName)) {
    this.advisorsCache.put(beanName, classAdvisors);
}
else {
    this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);

2.1. 建立一个MetadataAwareAspectInstanceFactory对象

以OperationAop.class为例,对象中包含的信息以下:

beanFactory = DefaultListableBeanFactory
name = "operationAop"
aspectMetadata = {AspectMetadata@3331} 

  其中aspectMetadata:
    aspectName = "operationAop"
    aspectClass = "class com.Hodey.analyseaop.aop.OperationAop"
    ajType = "com.Hodey.analyseaop.aop.OperationAop"
    perClausePointcut = "Pointcut.TRUE"

2.2. getAdvisors(factory)

this.advisorFactory.getAdvisors(factory) 解析和建立对一个代理工厂的advisor

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    validate(aspectClass);
    // 包装MetadataAwareAspectInstanceFactory一下,使得它只能被实例化1次
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new ArrayList<>();
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 尝试解析每一个方法,找到方法对应的切点和通知
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }
    // 代理默认不是懒加载的,这里的分支通常不会走进
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }    
    // 若是属性也有须要代理的,那么还须要寻找到属性的advisor
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }
    return advisors;
}

建立LazySingletonAspectInstanceFactoryDecorator的目的仅仅是包装传入的MetadataAwareAspectInstanceFactory,使得它是单例对象。getAdvisorMethods(Class<?> aspectClass)是获取传入class及其继承类的全部方法,以OperationAop.class为例获取的方法集以下:

0 = {Method@3112} "public int com.Hodey.analyseaop.aop.OperationAop.doAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable"
1 = {Method@3512} "public void com.Hodey.analyseaop.aop.OperationAop.doBefore()"
2 = {Method@3513} "public void com.Hodey.analyseaop.aop.OperationAop.doAfter()"
3 = {Method@3514} "protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException"
4 = {Method@3515} "public boolean java.lang.Object.equals(java.lang.Object)"
5 = {Method@3516} "protected void java.lang.Object.finalize() throws java.lang.Throwable"
6 = {Method@3517} "public final native java.lang.Class java.lang.Object.getClass()"
7 = {Method@3518} "public native int java.lang.Object.hashCode()"
8 = {Method@3519} "public final native void java.lang.Object.notify()"
9 = {Method@3520} "public final native void java.lang.Object.notifyAll()"
10 = {Method@3521} "private static native void java.lang.Object.registerNatives()"
11 = {Method@3522} "public java.lang.String java.lang.Object.toString()"
12 = {Method@3523} "public final void java.lang.Object.wait() throws java.lang.InterruptedException"
13 = {Method@3524} "public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException"
14 = {Method@3525} "public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException"

而后对这些方法尝试获取它的advisor。

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {

    // 得到切点
    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }
    // 找到了切点,就将切点、链接点、通知等aop参数封装成InstantiationModelAwarePointcutAdvisorImpl对象向上返回。
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

首先要去找到切点。可是进入getPointCut后从方法名上看为何第一步竟然是去找对应方法上的注解呢?别着急,咱们跟着流程一步步分析:

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }
    AspectJExpressionPointcut ajexp =
            new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
    // 由于aspectJAnnotation已经封装了切点pointcut的信息,因此直接拿出来设置到ajexp对象上便可。
    ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
    if (this.beanFactory != null) {
        ajexp.setBeanFactory(this.beanFactory);
    }
    return ajexp;
}


protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
    for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
        AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
        if (foundAnnotation != null) {
            return foundAnnotation;
        }
    }
    return null;
}

首先来看findAspectJAnnotationOnMethod方法。ASPECTJ_ANNOTATION_CLASSES中存放的是[Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class]数组。在for循环中会依次对方法上的注解和ASPECTJ_ANNOTATION_CLASSES中元素进行比对,找出对应注解的AspectJAnnotation。以OperationAop中的beforeAdd方法为例。该方法上有注解@Around("addCut()"),那么就会经过findAnnotation找到该注解, 在返回的结果中已经封装了切点位置,通知类型,切点的表达式和参数名等信息:

annotation = "@org.aspectj.lang.annotation.Around(argNames=, value=doCut())"
annotationType = "AtAround"
pointcutExpression = "doCut()"
argumentNames = ""

而后建立AspectJExpressionPointcut ajexp对象,将findAnnotation找到的结果中封装的相关切点信息设置到ajexp对象上,随后将这个带有切点信息的对象返回上层getAdvisor方法,随后在该方法中将切点、链接点、通知等aop参数封装成InstantiationModelAwarePointcutAdvisorImpl对象向上返回到getAdvisors方法,随后将返回值添加到List<Advisor> advisors中。等到遍历完全部方法,将advisors一路返回,最终返回到buildAspectJAdvisors中在advisorsCache缓存好advisors对象再一路返回到shouldSkip,本步骤执行完成。

2.3 getAdvice

值得一提的是再InstantiationModelAwarePointcutAdvisorImpl对象建立过程当中会调用instantiateAdvice实例化通知(advice),这个过程当中会调用getAdvice方法建立通知。

public Advice getAdvice(Method candidateAdviceMethod是, AspectJExpressionPointcut expressionPointcut,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    validate(candidateAspectClass);

    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }

    AbstractAspectJAdvice springAdvice;
    //根据不一样的注解,就会走不一样的分支建立各自的通知对象
    switch (aspectJAnnotation.getAnnotationType()) {
        case AtPointcut:
            return null;
        case AtAround:
            springAdvice = new AspectJAroundAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtBefore:            
            springAdvice = new AspectJMethodBeforeAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
        default:
            throw new UnsupportedOperationException(
                    "Unsupported advice type on method: " + candidateAdviceMethod);
    }

    // 最后再手动设置一些属性。
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    // 绑定参数
    // 若是第一个参数类型是JoinPoint或procedure edingjoinpoint,那么将在那个位置传递一个JoinPoint (procedure edingjoinpoint for around advice)。
    // 若是第一个参数是JoinPoint.StaticPart类型的,那么将会在对应位置绑定上一个JoinPoint.StaticPart参数。
    // 剩下的参数必须由给定链接点上的切入点求值绑定,以此获得一个从参数名到值的映射。咱们须要计算须要将哪一个通知参数绑定到哪一个参数名。肯定这种绑定有多种策略,它们以责任链的形式排列。
    springAdvice.calculateArgumentBindings();
    return springAdvice;
}

以建立建立OperationAop doBefore()方法的通知为例,传入的candidateAdviceMethod是切点方法。findAspectJAnnotationOnMethod(candidateAdviceMethod)获得的aspectJAnnotation对象结果以下:

annotation = "@org.aspectj.lang.annotation.Before(argNames=, value=doCut())"
annotationType = "AtBefore"
pointcutExpression = "doCut()"
argumentNames = ""

而后根据下面不一样的分支建立不一样的Advice。springAdvice.calculateArgumentBindings();是进行参数绑定。(过程复杂,暂时没看)


到此,Spring AOP的元数据解析过程基本上算是分析完毕了。下一篇文章将着重介绍AOP类的建立过程,敬请期待!

3. 附录:本工程项目文件

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HodayDouble {
}
@Aspect
@Component
public class OperationAop {

    @Pointcut("@annotation(com.Hodey.analyseaop.anno.HodayDouble)")
    public void doCut(){}

    @Around("doCut()")
    public int doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object[] args = proceedingJoinPoint.getArgs();
        int i = (int) args[0];
        int j = (int) args[1];
        System.out.println("入参:i:" + i);
        System.out.println("入参:j:" + j);
        System.out.println("before around");
        int result = (int) proceedingJoinPoint.proceed();
        System.out.println("after around");
        System.out.println("原始结果:" + result);

        result = result * 2;
        System.out.println("代理结果:" + result);
        return result;
    }

    @Before("doCut()")
    public void doBefore(){
        System.out.println("@Before print");
    }

    @After("doCut()")
    public void doAfter(){
        System.out.println("@After print");
    }
}
@Service("service")
public class OperationService {

    @Autowired
    private OperationUtil ops;

    public int add(int i , int j){
        return ops.add(i,j);
    }
}
@Component
public class OperationUtil {

    @HodayDouble
    public int add(int i, int j){
        int result = i + j;
        return result;
    }
}
@ComponentScan("com.Hodey")
@EnableAutoConfiguration
public class AnalyseAopApplication {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnalyseAopApplication.class);
		OperationService opsService = (OperationService) ctx.getBean("service");
		int result = opsService.add(2,3);
		System.out.println("最终结果:" + result);
	}
}

执行结果:

入参:i:2
入参:j:3
before around
@Before print
after around
原始结果:5
代理结果:10
@After print
最终结果:10