【一】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