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

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

引入

我们应该从哪里开始着手看Spring AOP的源码呢?和我们上文分析的IOC源码实现有什么关系呢?

  1. 前文中我们写了AOP的Demo,根据其XML配置我们不难发现AOP是基于IOC的Bean加载来实现的;这便使我们的主要入口

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

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

  1. 然后我们就能找到如下初始化的流程和aop对应的handler

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

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

(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 @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; } 

打个断点看下

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

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

@Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(         BeanDefinitionRegistry registry, @Nullable Object source) {      return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); } 

到这里,我们发现AOP的创建工作是交给AnnotationAwareAspectJAutoProxyCreator来完成的。

注解切面代理创建类(AnnotationAwareAspectJAutoProxyCreator)

AnnotationAwareAspectJAutoProxyCreator是如何工作的呢?这时候我们就要看AnnotationAwareAspectJAutoProxyCreator类结构关系了。

如下是类结构关系

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

它实现了两类接口:

  • BeanFactoryAware属于Bean级生命周期接口方法
  • InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”,是容器级生命周期接口方法

结合前文Spring Bean生命周期的流程

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

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

postProcessBeforeInstantiation

如下是上述类结构中postProcessBeforeInstantiation的方法,读者在自己看代码的时候建议打个断点看,可以方便理解

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

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

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

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

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

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

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

/**     * 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

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

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

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

findAnnotation方法如下

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

/**     * 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)     */ @Nullable public 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 @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)实现了。

/** * 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
    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框架和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处理请求的过程的源码解析。
发表评论

相关文章