1. 程式人生 > >spring5 原始碼深度解析----- 建立AOP代理之獲取增強器

spring5 原始碼深度解析----- 建立AOP代理之獲取增強器

在上一篇的博文中我們講解了通過自定義配置完成了對AnnotationAwareAspectJAutoProxyCreator型別的自動註冊,那麼這個類到底做了什麼工作來完成AOP的操作呢?首先我們看看AnnotationAwareAspectJAutoProxyCreator的層次結構,如下圖所示: 

從上圖的類層次結構圖中我們看到這個類實現了BeanPostProcessor介面,而實現BeanPostProcessor後,當Spring載入這個Bean時會在例項化前呼叫其postProcesssAfterIntialization方法,而我們對於AOP邏輯的分析也由此開始。

首先看下其父類AbstractAutoProxyCreator中的postProcessAfterInitialization方法:

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
        //根據給定的bean的class和name構建出個key,格式:beanClassName_beanName  
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            //如果它適合被代理,則需要封裝指定bean  
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

在上面的程式碼中用到了方法wrapIfNecessary,繼續跟蹤到方法內部:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 如果已經處理過
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 無需增強
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // 給定的bean類是否代表一個基礎設施類,基礎設施類不應代理,或者配置了指定bean不需要自動代理
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 如果存在增強方法則建立代理
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 如果獲取到了增強則需要針對增強建立代理
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 建立代理
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

函式中我們已經看到了代理建立的雛形。當然,真正開始之前還需要經過一些判斷,比如是否已經處理過或者是否是需要跳過的bean,而真正建立代理的程式碼是從getAdvicesAndAdvisorsForBean開始的。
建立代理主要包含了兩個步驟:
(1)獲取增強方法或者增強器;
(2)根據獲取的增強進行代理。 

其中邏輯複雜,我們首先來看看獲取增強方法的實現邏輯。是在AbstractAdvisorAutoProxyCreator中實現的,程式碼如下:

AbstractAdvisorAutoProxyCreator

protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

對於指定bean的增強方法的獲取一定是包含兩個步驟的,獲取所有的增強以及尋找所有增強中使用於bean的增強並應用,那麼findCandidateAdvisors與findAdvisorsThatCanApply便是做了這兩件事情。當然,如果無法找到對應的增強器便返回DO_NOT_PROXY,其中DO_NOT_PROXY=null。

獲取增強器

由於我們分析的是使用註解進行的AOP,所以對於findCandidateAdvisors的實現其實是由AnnotationAwareAspectJAutoProxyCreator類完成的,我們繼續跟蹤AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法。程式碼如下

@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // 當使用註解方式配置AOP的時候並不是丟棄了對XML配置的支援,
    // 在這裡呼叫父類方法載入配置檔案中的AOP宣告
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

AnnotationAwareAspectJAutoProxyCreator間接繼承了AbstractAdvisorAutoProxyCreator,在實現獲取增強的方法中除了保留父類的獲取配置檔案中定義的增強外,同時添加了獲取Bean的註解增強的功能,那麼其實現正是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()來實現的。
在真正研究程式碼之前讀者可以嘗試著自己去想象一下解析思路,看看自己的實現與Spring是否有差別呢?

(1)獲取所有beanName,這一步驟中所有在beanFactory中註冊的Bean都會被提取出來。
(2)遍歷所有beanName,並找出宣告AspectJ註解的類,進行進一步的處理。
(3)對標記為AspectJ註解的類進行增強器的提取。
(4)將提取結果加入快取。 

public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;

    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();
                // 獲取所有的beanName
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                // 迴圈所有的beanName找出對應的增強方法
                for (String beanName : beanNames) {
                    // 不合法的bean則略過,由子類定義規則,預設返回true
                    if (!isEligibleBean(beanName)) {
                        continue;
                    }
                    // We must be careful not to instantiate beans eagerly as in this case they
                    // would be cached by the Spring container but would not have been weaved.
                    // 獲取對應的bean的Class型別
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
                    // 如果存在Aspect註解
                    if (this.advisorFactory.isAspect(beanType)) {
                        aspectNames.add(beanName);
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // 解析標記Aspect註解中的增強方法
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            if (this.beanFactory.isSingleton(beanName)) {
                                //將增強器存入快取中,下次可以直接取
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            else {
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        }
                        else {
                            // Per target or per this.
                            if (this.beanFactory.isSingleton(beanName)) {
                                throw new IllegalArgumentException("Bean with name '" + beanName +
                                        "' is a singleton, but aspect instantiation model is not singleton");
                            }
                            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;
}

至此,我們已經完成了Advisor的提取,在上面的步驟中最為重要也最為繁雜的就是增強器的獲取,而這一切功能委託給了getAdvisors方法去實現(this.advisorFactory.getAdvisors(factory))。

我們先來看看 this.advisorFactory.isAspect(beanType)

@Override
public boolean isAspect(Class<?> clazz) {
    return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
    return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

@Nullable
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
    try {
        //判斷此Class 是否存在Aspect.class註解
        A annotation = clazz.getDeclaredAnnotation(annotationType);
        if (annotation != null) {
            return annotation;
        }
        for (Annotation declaredAnn : getDeclaredAnnotations(clazz)) {
            Class<? extends Annotation> declaredType = declaredAnn.annotationType();
            if (!isInJavaLangAnnotationPackage(declaredType) && visited.add(declaredAnn)) {
                annotation = findAnnotation(declaredType, annotationType, visited);
                if (annotation != null) {
                    return annotation;
                }
            }
        }
    }
}

如果 bean 存在 Aspect.class註解,就可以獲取此bean中的增強器了,接著我們來看看 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 獲取標記為AspectJ的類
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 獲取標記為AspectJ的name
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new ArrayList<>();
    
    // 對aspectClass的每一個帶有註解的方法進行迴圈(帶有PointCut註解的方法除外),取得Advisor,並新增到集合裡。
    // (這是裡應該是取得Advice,然後取得我們自己定義的切面類中PointCut,組合成Advisor)
    for (Method method : getAdvisorMethods(aspectClass)) {
        //將類中的方法封裝成Advisor
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}

普通增強器的獲取

普通增強器的獲取邏輯通過getAdvisor方法實現,實現步驟包括對切點的註解的獲取以及根據註解資訊生成增強。我們先來看看 getAdvisorMethods(aspectClass),這個方法,通過很巧妙的使用介面,定義一個匿名回撥,把帶有註解的Method都取得出來,放到集合裡

private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    final List<Method> methods = new LinkedList<Method>();
    ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
        @Override
        public void doWith(Method method) throws IllegalArgumentException {
            // Exclude pointcuts
            // 將沒有使用Pointcut.class註解的方法加入到集合中
            if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                methods.add(method);
            }
        }
    });
    Collections.sort(methods, METHOD_COMPARATOR);
    return methods;
}

public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
    // Keep backing up the inheritance hierarchy.
    // 通過反射獲取類中所有的方法
    Method[] methods = getDeclaredMethods(clazz);
    //遍歷所有的方法
    for (Method method : methods) {
        if (mf != null && !mf.matches(method)) {
            continue;
        }
        try {
            //呼叫函式體
            mc.doWith(method);
        }
        catch (IllegalAccessException ex) {
            throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
        }
    }
    if (clazz.getSuperclass() != null) {
        doWithMethods(clazz.getSuperclass(), mc, mf);
    }
    else if (clazz.isInterface()) {
        for (Class<?> superIfc : clazz.getInterfaces()) {
            doWithMethods(superIfc, mc, mf);
        }
    }
}

普通增強器的獲取邏輯通過 getAdvisor 方法來實現,實現步驟包括對切點的註解以及根據註解資訊生成增強。

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

    validate(aif.getAspectMetadata().getAspectClass());
    // 獲取PointCut資訊(主要是PointCut裡的表示式)
    // 把Method物件也傳進去的目的是,比較Method物件上的註解,是不是下面註解其中一個
    // 如果不是,返回null;如果是,就把取得PointCut內容包裝返回
    // 被比較註解:Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class
    AspectJExpressionPointcut ajexp =
            getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
    if (ajexp == null) {
        return null;
    }
    // 根據PointCut資訊生成增強器
    return new InstantiationModelAwarePointcutAdvisorImpl(
            this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
}

(1)切點資訊的獲取 

所謂獲取切點資訊就是指定註解的表示式資訊的獲取,如@Before("test()")。

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
    // 獲取方法上的註解
    // 比較Method物件上的註解,是不是下面註解其中一個,如果不是返回null
    // 被比較註解:Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class
    AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }
    // 使用AspectJExpressionPointcut 例項封裝獲取的資訊
    AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);

    // 提取得到的註解中的表示式如:
    // @Pointcut("execution(* test.TestBean.*(..))")
    ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
    return ajexp;
}

詳細看下上面方法中使用到的方法findAspectJAnnotationOnMethod

protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
    // 設定要查詢的註解類,看看方法的上註解是不是這些註解其中之一
    Class<?>[] classesToLookFor = new Class<?>[] {
            Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
    for (Class<?> c : classesToLookFor) {
        AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
        if (foundAnnotation != null) {
            return foundAnnotation;
        }
    }
    return null;
}

在上面方法中又用到了方法findAnnotation,繼續跟蹤程式碼:

// 獲取指定方法上的註解並使用 AspectJAnnotation 封裝
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
    A result = AnnotationUtils.findAnnotation(method, toLookFor);
    if (result != null) {
        return new AspectJAnnotation<A>(result);
    }
    else {
        return null;
    }
}

此方法的功能是獲取指定方法上的註解並使用AspectJAnnotation封裝。 

(2)根據切點資訊生成增強類 

所有的增強都有Advisor實現類InstantiationModelAwarePontcutAdvisorImpl進行統一封裝的。我們看下其建構函式:

public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
        MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {

    this.declaredPointcut = ajexp;
    this.method = method;
    this.atAspectJAdvisorFactory = af;
    this.aspectInstanceFactory = aif;
    this.declarationOrder = declarationOrderInAspect;
    this.aspectName = aspectName;

    if (aif.getAspectMetadata().isLazilyInstantiated()) {
        // Static part of the pointcut is a lazy type.
        Pointcut preInstantiationPointcut =
                Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

        // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
        // If it's not a dynamic pointcut, it may be optimized out
        // by the Spring AOP infrastructure after the first evaluation.
        this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif);
        this.lazy = true;
    }
    else {
        // A singleton aspect.
        // 初始化Advice
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
        this.pointcut = declaredPointcut;
        this.lazy = false;
    }
}

通過對上面建構函式的分析,發現封裝過程只是簡單地將資訊封裝在類的例項中,所有的額資訊單純地複製。在例項初始化的過程中還完成了對於增強器的初始化。因為不同的增強所體現的邏輯是不同的,比如@Before(“test()”)與After(“test()”)標籤的不同就是增強器增強的位置不同,所以就需要不同的增強器來完成不同的邏輯,而根據註解中的資訊初始化對應的額增強器就是在instantiateAdvice函式中實現的,繼續跟蹤程式碼:

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
            this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}

    @Override
@Nullable
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;
    }

    // If we get here, we know we have an AspectJ method.
    // Check that it's an AspectJ-annotated class
    if (!isAspect(candidateAspectClass)) {
        throw new AopConfigException("Advice must be declared inside an aspect type: " +
                "Offending method '" + candidateAdviceMethod + "' in class [" +
                candidateAspectClass.getName() + "]");
    }

    if (logger.isDebugEnabled()) {
        logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    }

    AbstractAspectJAdvice springAdvice;
    // 根據不同的註解型別封裝不同的增強器
    switch (aspectJAnnotation.getAnnotationType()) {
        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;
        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;
}

從上述函式程式碼中可以看到,Spring會根據不同的註解生成不同的增強器,正如程式碼switch (aspectJAnnotation.getAnnotationType()),根據不同的型別來生成。例如AtBefore會對應AspectJMethodBeforeAdvice。在AspectJMethodBeforeAdvice中完成了增強邏輯,這裡的 AspectJMethodBeforeAdvice 最後會被介面卡封裝成MethodBeforeAdviceInterceptor,下一篇文章中我們具體分析,具體看下其程式碼:

MethodBeforeAdviceInterceptor

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

    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 {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }

}

其中的MethodBeforeAdvice代表著前置增強的AspectJMethodBeforeAdvice,跟蹤before方法:

AspectJMethodBeforeAdvice.java

public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {

    public AspectJMethodBeforeAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }


    @Override
    public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
        //直接呼叫增強方法
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }

}

protected Object invokeAdviceMethod(
        @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
        throws Throwable {

    return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        // TODO AopUtils.invokeJoinpointUsingReflection
        // 通過反射呼叫AspectJ註解類中的增強方法
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    }
    catch (IllegalArgumentException ex) {
        throw new AopInvocationException("Mismatch on arguments to advice method [" +
                this.aspectJAdviceMethod + "]; pointcut expression [" +
                this.pointcut.getPointcutExpression() + "]", ex);
    }
    catch (InvocationTargetException ex) {
        throw ex.getTargetException();
    }
}

invokeAdviceMethodWithGivenArgs方法中的aspectJAdviceMethod正是對與前置增強的方法,在這裡實現了呼叫。

後置增強與前置增強有稍許不一致的地方。回顧之前講過的前置增強,大致的結構是在攔截器鏈中放置MethodBeforeAdviceInterceptor,而在MethodBeforeAdviceInterceptor中又放置了AspectJMethodBeforeAdvice,並在呼叫invoke時首先串聯呼叫。但是在後置增強的時候卻不一樣,沒有提供中間的類,而是直接在攔截器中使用了中間的AspectJAfterAdvice,也就是直接實現了MethodInterceptor。

public class AspectJAfterAdvice extends AbstractAspectJAdvice
        implements MethodInterceptor, AfterAdvice, Serializable {

    public AspectJAfterAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }


    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        finally {
            // 啟用增強方法
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }

    @Override
    public boolean isBeforeAdvice() {
        return false;
    }

    @Override
    public boolean isAfterAdvice() {
        return true;
    }

}

其他的幾個增強器,留在下一篇文章中具體來看

尋找匹配的增強器

前面的函式中已經完成了所有增強器的解析,但是對於所有增強器來講,並不一定都適用於當前的bean,還要挑取出適合的增強器,也就是滿足我們配置的萬用字元的增強器。具體實現在findAdvisorsThatCanApply中。

protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        // 過濾已經得到的advisors
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}

繼續看findAdvisorsThatCanApply:

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    // 首先處理引介增強
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
            eligibleAdvisors.add(candidate);
        }
    }
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor) {
            // already processed
            continue;
        }
        // 對於普通bean的處理
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}

findAdvisorsThatCanApply函式的主要功能是尋找增強器中適用於當前class的增強器。引介增強與普通的增強的處理是不一樣的,所以分開處理。而對於真正的匹配在canApply中實現。

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    else if (advisor instanceof PointcutAdvisor) {
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    }
    else {
        // It doesn't have a pointcut so we assume it applies.
        return true;
    }
}

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    Assert.notNull(pc, "Pointcut must not be null");
    //通過Pointcut的條件判斷此類是否能匹配
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }

    MethodMatcher methodMatcher = pc.getMethodMatcher();
    if (methodMatcher == MethodMatcher.TRUE) {
        // No need to iterate the methods if we're matching any method anyway...
        return true;
    }

    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }

    Set<Class<?>> classes = new LinkedHashSet<>();
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

    for (Class<?> clazz : classes) {
        //反射獲取類中所有的方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            //根據匹配原則判斷該方法是否能匹配Pointcut中的規則,如果有一個方法能匹配,則返回true
            if (introductionAwareMethodMatcher != null ?
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    return false;
}

首先判斷bean是否滿足切點的規則,如果能滿足,則獲取bean的所有方法,判斷是否有方法能匹配規則,有方法匹配規則,就代表此 Advisor 能作用於該bean,然後將該Advisor加入 eligibleAdvisors 集合中。

我們以註解的規則來看看bean中的method是怎樣匹配 Pointcut中的規則

AnnotationMethodMatcher

@Override
public boolean matches(Method method, Class<?> targetClass) {
    if (matchesMethod(method)) {
        return true;
    }
    // Proxy classes never have annotations on their redeclared methods.
    if (Proxy.isProxyClass(targetClass)) {
        return false;
    }
    // The method may be on an interface, so let's check on the target class as well.
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
    return (specificMethod != method && matchesMethod(specificMethod));
}

private boolean matchesMethod(Method method) {
    //可以看出判斷該Advisor是否使用於bean中的method,只需看method上是否有Advisor的註解
    return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) :
            method.isAnnotationPresent(this.annotationType));
}

至此,我們在後置處理器中找到了所有匹配Bean中的增強器,下一章講解如何使用找到切面,來建立代理。

&n