Spring框架系列(9)-SpringAOP实现原理详解之AOP切面的实现

博客 动态
0 321
优雅殿下
优雅殿下 2022-06-30 08:01:16
悬赏:0 积分 收藏

Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现

前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的。本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor,为后续交给代理增强实现做准备的过程)。@pdai

  • Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现
    • 引入
    • aop配置标签的解析
      • config配置标签的解析
      • aspectj-autoproxy配置标签的解析
    • 注解切面代理创建类(AnnotationAwareAspectJAutoProxyCreator)
      • postProcessBeforeInstantiation
        • 判断是否是aop基础类
        • 是否应该跳过shouldSkip
        • 切面方法转成Advisor
        • 获取表达式的切点
        • 封装成Advisor
        • 小结
      • postProcessAfterInitialization
    • 总结
    • 更多文章

引入

我们应该从哪里开始着手看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来处理。

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方法

@Override@Nullablepublic 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的方法如下, 处理方法不难,我这里就不展开了

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 方法

@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {    // 注册AspectJAnnotationAutoProxyCreator    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);    // 拓展BeanDefinition    extendBeanDefinition(element, parserContext);    return null;}

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法对应如下

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对应如下

@Nullablepublic 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的方法,读者在自己看代码的时候建议打个断点看,可以方便理解

@Overridepublic 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 如下

@Overrideprotected 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接口。

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配置的通知是对应的

@Overrideprotected 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方法如下:

@Overrideprotected 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方法如下

/**    * Look for AspectJ-annotated aspect beans in the current bean factory,    * and return to a list of Spring AOP Advisors representing them.    * <p>Creates a Spring Advisor for each AspectJ advice method.    * @return the list of {@link org.springframework.aop.Advisor} beans    * @see #isEligibleBean    */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<>();                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

@Overridepublic List<Advisor> 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方法如下

@Override@Nullablepublic 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如下:

@Nullableprivate 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的方法如下

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 <i>should</i> only be one anyway...).    */@SuppressWarnings("unchecked")@Nullableprotected 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;}

findAnnotation方法如下

@Nullableprivate 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 获取注解方法如下

/**    * 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 <em>directly present</em> on the given    * method itself.    * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.    * <p>Meta-annotations will be searched if the annotation is not    * <em>directly present</em> on the method.    * <p>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)    */@Nullablepublic static <A extends Annotation> A findAnnotation(Method method, @Nullable Class<A> 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构造完成

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

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获取

@Override@Nullablepublic 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)实现了。

/*** Create a proxy with the configured interceptors if the bean is* identified as one to proxy by the subclass.* @see #getAdvicesAndAdvisorsForBean*/@Overridepublic 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;}

后文中将分别介绍代理的创建和实现:

  • Spring进阶 - Spring AOP实现原理详解之AOP代理的创建
  • Spring进阶 - Spring AOP实现原理详解之Cglib代理实现
  • Spring进阶 - Spring AOP实现原理详解之JDK代理实现

总结

通过上文的分析,我们做下小结:

  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
    1. postProcessBeforeInstantiation:主要是处理使用了@Aspect注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor
    2. postProcessAfterInitialization:主要负责将Advisor注入到合适的位置,创建代理(cglib或jdk),为后面给代理进行增强实现做准备。

更多文章

首先, 从Spring框架的整体架构和组成对整体框架有个认知。

  • Spring基础 - Spring和Spring框架组成
    • Spring是什么?它是怎么诞生的?有哪些主要的组件和核心功能呢? 本文通过这几个问题帮助你构筑Spring和Spring Framework的整体认知。

其次,通过案例引出Spring的核心(IoC和AOP),同时对IoC和AOP进行案例使用分析。

  • Spring基础 - Spring简单例子引入Spring的核心
    • 上文中我们简单介绍了Spring和Spring Framework的组件,那么这些Spring Framework组件是如何配合工作的呢?本文主要承接上文,向你展示Spring Framework组件的典型应用场景和基于这个场景设计出的简单案例,并以此引出Spring的核心要点,比如IOC和AOP等;在此基础上还引入了不同的配置方式, 如XML,Java配置和注解方式的差异。
  • Spring基础 - Spring核心之控制反转(IOC)
    • 在Spring基础 - Spring简单例子引入Spring的核心中向你展示了IoC的基础含义,同时以此发散了一些IoC相关知识点; 本节将在此基础上进一步解读IOC的含义以及IOC的使用方式
  • Spring基础 - Spring核心之面向切面编程(AOP)
    • 在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及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处理请求的过程的源码解析。
posted @ 2022-06-30 07:27 pdai 阅读(12) 评论(0) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员