Spring框架系列(9) - Spring AOP實現原理詳解之AOP切面的實現

語言: CN / TW / HK

前文,我們分析了Spring IOC的初始化過程和Bean的生命週期等,而Spring AOP也是基於IOC的Bean載入來實現的。本文主要介紹Spring AOP原理解析的切面實現過程(將切面類的所有切面方法根據使用的註解生成對應Advice,並將Advice連同切入點匹配器和切面類等資訊一併封裝到Advisor,為後續交給代理增強實現做準備的過程)。@pdai

引入

我們應該從哪裡開始著手看Spring AOP的原始碼呢?和我們上文分析的IOC原始碼實現有什麼關係呢?

  1. 前文中我們寫了AOP的Demo,根據其XML配置我們不難發現AOP是基於IOC的Bean載入來實現的;這便使我們的主要入口

所以理解Spring AOP的初始化必須要先理解Spring IOC的初始化

  1. 然後我們就能找到如下初始化的流程和aop對應的handler

即parseCustomElement方法找到parse aop:aspectj-autoproxy的handler(org.springframework.aop.config.AopNamespaceHandler)

(PS:其實你會發現,最重要的是知識點的關聯關係,而不是知識點本身,就後續程式碼而言不就是打個斷點慢慢看的事了麼。)

aop配置標籤的解析

上文中,我們找到了AopNamespaceHandler,其實就是註冊BeanDefinition的解析器BeanDefinitionParser,將aop:xxxxxx配置標籤交給指定的parser來處理。

```java public class AopNamespaceHandler extends NamespaceHandlerSupport {

/**
 * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
 * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
 * and '{@code scoped-proxy}' tags.
 */
@Override
public void init() {
    // In 2.0 XSD as well as in 2.5+ XSDs
    // 註冊解析<aop:config> 配置
    registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
    // 註冊解析<aop:aspectj-autoproxy> 配置
    registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
    registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

    // Only in 2.0 XSD: moved to context namespace in 2.5+
    registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

} ```

config配置標籤的解析

<aop:config/>由ConfigBeanDefinitionParser這個類處理,作為parser類最重要的就是parse方法

```java @Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef);

configureAutoProxyCreator(parserContext, element);

List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
    String localName = parserContext.getDelegate().getLocalName(elt);
    if (POINTCUT.equals(localName)) {
        parsePointcut(elt, parserContext);
    }
    else if (ADVISOR.equals(localName)) {
        parseAdvisor(elt, parserContext);
    }
    else if (ASPECT.equals(localName)) {
        parseAspect(elt, parserContext);
    }
}

parserContext.popAndRegisterContainingComponent();
return null;

} ```

打個斷點看下

parseAspect的方法如下, 處理方法不難,我這裡就不展開了

```java private void parseAspect(Element aspectElement, ParserContext parserContext) { String aspectId = aspectElement.getAttribute(ID); String aspectName = aspectElement.getAttribute(REF);

try {
    this.parseState.push(new AspectEntry(aspectId, aspectName));
    List<BeanDefinition> beanDefinitions = new ArrayList<>();
    List<BeanReference> beanReferences = new ArrayList<>();

    List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
    for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
        Element declareParentsElement = declareParents.get(i);
        beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
    }

    // We have to parse "advice" and all the advice kinds in one loop, to get the
    // ordering semantics right.
    NodeList nodeList = aspectElement.getChildNodes();
    boolean adviceFoundAlready = false;
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node node = nodeList.item(i);
        if (isAdviceNode(node, parserContext)) {
            if (!adviceFoundAlready) {
                adviceFoundAlready = true;
                if (!StringUtils.hasText(aspectName)) {
                    parserContext.getReaderContext().error(
                            "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
                            aspectElement, this.parseState.snapshot());
                    return;
                }
                beanReferences.add(new RuntimeBeanReference(aspectName));
            }
            AbstractBeanDefinition advisorDefinition = parseAdvice(
                    aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
            beanDefinitions.add(advisorDefinition);
        }
    }

    AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
            aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
    parserContext.pushContainingComponent(aspectComponentDefinition);

    List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
    for (Element pointcutElement : pointcuts) {
        parsePointcut(pointcutElement, parserContext);
    }

    parserContext.popAndRegisterContainingComponent();
}
finally {
    this.parseState.pop();
}

} ```

aspectj-autoproxy配置標籤的解析

<aop:aspectj-autoproxy/>則由AspectJAutoProxyBeanDefinitionParser這個類處理的,我們看下parse 方法

java @Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { // 註冊AspectJAnnotationAutoProxyCreator AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); // 拓展BeanDefinition extendBeanDefinition(element, parserContext); return null; }

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法對應如下

```java public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) {

BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);

} ```

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary對應如下

```java @Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) {

return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);

} ```

到這裡,我們發現AOP的建立工作是交給AnnotationAwareAspectJAutoProxyCreator來完成的。

註解切面代理建立類(AnnotationAwareAspectJAutoProxyCreator)

AnnotationAwareAspectJAutoProxyCreator是如何工作的呢?這時候我們就要看AnnotationAwareAspectJAutoProxyCreator類結構關係了。

如下是類結構關係

它實現了兩類介面:

  • BeanFactoryAware屬於Bean級生命週期介面方法
  • InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個介面實現,一般稱它們的實現類為“後處理器”,是容器級生命週期介面方法

結合前文Spring Bean生命週期的流程

我們就可以定位到核心的初始化方法肯定在postProcessBeforeInstantiation和postProcessAfterInitialization中。

postProcessBeforeInstantiation

如下是上述類結構中postProcessBeforeInstantiation的方法,讀者在自己看程式碼的時候建議打個斷點看,可以方便理解

```java @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName);

if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
    // 如果已經在快取中,則忽略
    if (this.advisedBeans.containsKey(cacheKey)) {
        return null;
    }
    // 是否是aop基礎類?是否跳過?
    if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return null;
    }
}

// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
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;

} ```

判斷是否是aop基礎類

是否是aop基礎類的判斷方法 isInfrastructureClass 如下

java @Override protected boolean isInfrastructureClass(Class<?> beanClass) { // Previously we setProxyTargetClass(true) in the constructor, but that has too // broad an impact. Instead we now override isInfrastructureClass to avoid proxying // aspects. I'm not entirely happy with that as there is no good reason not // to advise aspects, except that it causes advice invocation to go through a // proxy, and if the aspect implements e.g the Ordered interface it will be // proxied by that interface and fail at runtime as the advice method is not // defined on the interface. We could potentially relax the restriction about // not advising aspects in the future. // 父類判斷它是aop基礎類 or 使用@Aspect註解 return (super.isInfrastructureClass(beanClass) || (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass))); }

父類判斷它是否是aop基礎類的方法 super.isInfrastructureClass(beanClass), 本質上就是判斷該類是否實現了Advice, Pointcut, Advisor或者AopInfrastructureBean介面。

java protected boolean isInfrastructureClass(Class<?> beanClass) { // 該類是否實現了Advice, Pointcut, Advisor或者AopInfrastructureBean介面 boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass); if (retVal && logger.isTraceEnabled()) { logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]"); } return retVal; }

是否應該跳過shouldSkip

通過斷點輔助,candidateAdvisors是就是xml配置的通知是對應的

java @Override protected boolean shouldSkip(Class<?> beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName); }

切面方法轉成Advisor

findCandidateAdvisors方法如下:

java @Override protected List<Advisor> findCandidateAdvisors() { // 在父類中找到所有的advisor:基於xml配置的<aop:before/>生成的 List<Advisor> advisors = super.findCandidateAdvisors(); // 為bean Factory中AspectJ切面構建advistor:通過AspectJ註解的方式生成Advisor類 if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }

在當前的bean Factory中通過AspectJ註解的方式生成Advisor類,buildAspectJAdvisors方法如下

```java /* * Look for AspectJ-annotated aspect beans in the current bean factory, * and return to a list of Spring AOP Advisors representing them. *

Creates a Spring Advisor for each AspectJ advice method. * @return the list of {@link org.springframework.aop.Advisor} beans * @see #isEligibleBean / public List buildAspectJAdvisors() { List aspectNames = this.aspectBeanNames;

if (aspectNames == null) {
    synchronized (this) {
        aspectNames = this.aspectBeanNames;
        if (aspectNames == null) {
            List<Advisor> advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Object.class, true, false);
            for (String beanName : beanNames) {
                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.
                Class<?> beanType = this.beanFactory.getType(beanName, false);
                if (beanType == null) {
                    continue;
                }
                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);
                        List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                        // 單例加到advisorsCache, 非單例加到aspectFactoryCache
                        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);
                        // advisorFactory工廠獲取advisors
                        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;

} ```

上述方法本質上的思路是:用DCL雙重鎖的單例實現方式,拿到切面類裡的切面方法,將其轉換成advisor(並放入快取中)。

轉換的成advisor的方法是:this.advisorFactory.getAdvisors

```java @Override public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); 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<>();
for (Method method : getAdvisorMethods(aspectClass)) {
    // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
    // to getAdvisor(...) to represent the "current position" in the declared methods list.
    // However, since Java 7 the "current position" is not valid since the JDK no longer
    // returns declared methods in the order in which they are declared in the source code.
    // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
    // discovered via reflection in order to support reliable advice ordering across JVM launches.
    // Specifically, a value of 0 aligns with the default value used in
    // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
    Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, 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方法如下

```java @Override @Nullable public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {

validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

AspectJExpressionPointcut expressionPointcut = getPointcut(
        candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
    return null;
}

// 封裝成advisor
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
        this, aspectInstanceFactory, declarationOrderInAspect, aspectName);

} ```

獲取表示式的切點

獲取表示式的切點的方法getPointcut如下:

```java @Nullable 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]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
    ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;

} ```

AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod的方法如下

```java private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] { Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

/* * Find and return the first AspectJ annotation on the given method * (there should only be one anyway...). / @SuppressWarnings("unchecked") @Nullable protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) { for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) { AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class) clazz); if (foundAnnotation != null) { return foundAnnotation; } } return null; } ```

findAnnotation方法如下

java @Nullable 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<>(result); } else { return null; } }

AnnotationUtils.findAnnotation 獲取註解方法如下

```java /* * Find a single {@link Annotation} of {@code annotationType} on the supplied * {@link Method}, traversing its super methods (i.e. from superclasses and * interfaces) if the annotation is not directly present on the given * method itself. *

Correctly handles bridge {@link Method Methods} generated by the compiler. *

Meta-annotations will be searched if the annotation is not * directly present on the method. *

Annotations on methods are not inherited by default, so we need to handle * this explicitly. * @param method the method to look for annotations on * @param annotationType the annotation type to look for * @return the first matching annotation, or {@code null} if not found * @see #getAnnotation(Method, Class) / @Nullable public static A findAnnotation(Method method, @Nullable Class annotationType) { if (annotationType == null) { return null; }

// Shortcut: directly present on the element, with no merging needed?
if (AnnotationFilter.PLAIN.matches(annotationType) ||
        AnnotationsScanner.hasPlainJavaAnnotationsOnly(method)) {
    return method.getDeclaredAnnotation(annotationType);
}

// Exhaustive retrieval of merged annotations...
return MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
        .get(annotationType).withNonMergedAttributes()
        .synthesize(MergedAnnotation::isPresent).orElse(null);

} ```

封裝成Advisor

注:Advisor 是 advice的包裝器,包含了advice及其它資訊

由InstantiationModelAwarePointcutAdvisorImpl構造完成

```java public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;

if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
    // Static part of the pointcut is a lazy type.
    Pointcut preInstantiationPointcut = Pointcuts.union(
            aspectInstanceFactory.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, aspectInstanceFactory);
    this.lazy = true;
}
else {
    // A singleton aspect.
    this.pointcut = this.declaredPointcut;
    this.lazy = false;
    this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}

}

```

通過pointcut獲取advice

java 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); }

交給aspectJAdvisorFactory獲取

```java @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);
}

// 切面註解轉換成advice
AbstractAspectJAdvice springAdvice;

switch (aspectJAnnotation.getAnnotationType()) {
    case AtPointcut: // AtPointcut忽略
        if (logger.isDebugEnabled()) {
            logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
        }
        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);
}

// 最後將其它切面資訊配置到advice
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
    springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();

return springAdvice;

} ```

小結

回頭看,主要是處理使用了@Aspect註解的切面類,然後將切面類的所有切面方法根據使用的註解生成對應Advice,並將Advice連同切入點匹配器和切面類等資訊一併封裝到Advisor的過程。

postProcessAfterInitialization

有了Adisor, 注入到合適的位置並交給代理(cglib和jdk)實現了。

java /** * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */ @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }

後文中將分別介紹代理的建立和實現:

總結

通過上文的分析,我們做下小結:

  1. IOC Bean載入方法棧中找到parseCustomElement方法,找到parse aop:aspectj-autoproxy的handler(org.springframework.aop.config.AopNamespaceHandler)
  2. AopNamespaceHandler註冊了<aop:aspectj-autoproxy/>的解析類是AspectJAutoProxyBeanDefinitionParser
  3. AspectJAutoProxyBeanDefinitionParser的parse 方法 通過AspectJAwareAdvisorAutoProxyCreator類去建立
  4. AspectJAwareAdvisorAutoProxyCreator實現了兩類介面,BeanFactoryAware和BeanPostProcessor;根據Bean生命週期方法找到兩個核心方法:postProcessBeforeInstantiation和postProcessAfterInitialization
  5. postProcessBeforeInstantiation:主要是處理使用了@Aspect註解的切面類,然後將切面類的所有切面方法根據使用的註解生成對應Advice,並將Advice連同切入點匹配器和切面類等資訊一併封裝到Advisor
  6. postProcessAfterInitialization:主要負責將Advisor注入到合適的位置,建立代理(cglib或jdk),為後面給代理進行增強實現做準備。

更多文章

首先, 從Spring框架的整體架構和組成對整體框架有個認知。

  • Spring基礎 - Spring和Spring框架組成
  • Spring是什麼?它是怎麼誕生的?有哪些主要的元件和核心功能呢? 本文通過這幾個問題幫助你構築Spring和Spring Framework的整體認知。

其次,通過案例引出Spring的核心(IoC和AOP),同時對IoC和AOP進行案例使用分析。

基於Spring框架和IOC,AOP的基礎,為構建上層web應用,需要進一步學習SpringMVC。

  • Spring基礎 - SpringMVC請求流程和案例
  • 前文我們介紹了Spring框架和Spring框架中最為重要的兩個技術點(IOC和AOP),那我們如何更好的構建上層的應用呢(比如web 應用),這便是SpringMVC;Spring MVC是Spring在Spring Container Core和AOP等技術基礎上,遵循上述Web MVC的規範推出的web開發框架,目的是為了簡化Java棧的web開發。 本文主要介紹SpringMVC的請求流程和基礎案例的編寫和執行。

Spring進階 - IoC,AOP以及SpringMVC的原始碼分析

  • Spring進階 - Spring IOC實現原理詳解之IOC體系結構設計
  • 在對IoC有了初步的認知後,我們開始對IOC的實現原理進行深入理解。本文將幫助你站在設計者的角度去看IOC最頂層的結構設計
  • Spring進階 - Spring IOC實現原理詳解之IOC初始化流程
  • 上文,我們看了IOC設計要點和設計結構;緊接著這篇,我們可以看下原始碼的實現了:Spring如何實現將資源配置(以xml配置為例)通過載入,解析,生成BeanDefination並註冊到IoC容器中的
  • Spring進階 - Spring IOC實現原理詳解之Bean例項化(生命週期,迴圈依賴等)
  • 上文,我們看了IOC設計要點和設計結構;以及Spring如何實現將資源配置(以xml配置為例)通過載入,解析,生成BeanDefination並註冊到IoC容器中的;容器中存放的是Bean的定義即BeanDefinition放到beanDefinitionMap中,本質上是一個ConcurrentHashMap<String, Object>;並且BeanDefinition介面中包含了這個類的Class資訊以及是否是單例等。那麼如何從BeanDefinition中例項化Bean物件呢,這是本文主要研究的內容?
  • Spring進階 - Spring AOP實現原理詳解之切面實現
  • 前文,我們分析了Spring IOC的初始化過程和Bean的生命週期等,而Spring AOP也是基於IOC的Bean載入來實現的。本文主要介紹Spring AOP原理解析的切面實現過程(將切面類的所有切面方法根據使用的註解生成對應Advice,並將Advice連同切入點匹配器和切面類等資訊一併封裝到Advisor,為後續交給代理增強實現做準備的過程)。
  • Spring進階 - Spring AOP實現原理詳解之AOP代理
  • 上文我們介紹了Spring AOP原理解析的切面實現過程(將切面類的所有切面方法根據使用的註解生成對應Advice,並將Advice連同切入點匹配器和切面類等資訊一併封裝到Advisor)。本文在此基礎上繼續介紹,代理(cglib代理和JDK代理)的實現過程。
  • Spring進階 - Spring AOP實現原理詳解之Cglib代理實現
  • 我們在前文中已經介紹了SpringAOP的切面實現和建立動態代理的過程,那麼動態代理是如何工作的呢?本文主要介紹Cglib動態代理的案例和SpringAOP實現的原理。
  • Spring進階 - Spring AOP實現原理詳解之JDK代理實現
  • 上文我們學習了SpringAOP Cglib動態代理的實現,本文主要是SpringAOP JDK動態代理的案例和實現部分。
  • Spring進階 - SpringMVC實現原理之DispatcherServlet初始化的過程
  • 前文我們有了IOC的原始碼基礎以及SpringMVC的基礎,我們便可以進一步深入理解SpringMVC主要實現原理,包含DispatcherServlet的初始化過程和DispatcherServlet處理請求的過程的原始碼解析。本文是第一篇:DispatcherServlet的初始化過程的原始碼解析。
  • Spring進階 - SpringMVC實現原理之DispatcherServlet處理請求的過程
  • 前文我們有了IOC的原始碼基礎以及SpringMVC的基礎,我們便可以進一步深入理解SpringMVC主要實現原理,包含DispatcherServlet的初始化過程和DispatcherServlet處理請求的過程的原始碼解析。本文是第二篇:DispatcherServlet處理請求的過程的原始碼解析。