前文,我们分析了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来处理。

  1. public class AopNamespaceHandler extends NamespaceHandlerSupport {
  2. /**
  3. * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
  4. * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
  5. * and '{@code scoped-proxy}' tags.
  6. */
  7. @Override
  8. public void init() {
  9. // In 2.0 XSD as well as in 2.5+ XSDs
  10. // 注册解析<aop:config> 配置
  11. registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
  12. // 注册解析<aop:aspectj-autoproxy> 配置
  13. registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
  14. registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
  15. // Only in 2.0 XSD: moved to context namespace in 2.5+
  16. registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
  17. }
  18. }

config配置标签的解析

<aop:config/>由ConfigBeanDefinitionParser这个类处理,作为parser类最重要的就是parse方法

  1. @Override
  2. @Nullable
  3. public BeanDefinition parse(Element element, ParserContext parserContext) {
  4. CompositeComponentDefinition compositeDef =
  5. new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
  6. parserContext.pushContainingComponent(compositeDef);
  7. configureAutoProxyCreator(parserContext, element);
  8. List<Element> childElts = DomUtils.getChildElements(element);
  9. for (Element elt: childElts) {
  10. String localName = parserContext.getDelegate().getLocalName(elt);
  11. if (POINTCUT.equals(localName)) {
  12. parsePointcut(elt, parserContext);
  13. }
  14. else if (ADVISOR.equals(localName)) {
  15. parseAdvisor(elt, parserContext);
  16. }
  17. else if (ASPECT.equals(localName)) {
  18. parseAspect(elt, parserContext);
  19. }
  20. }
  21. parserContext.popAndRegisterContainingComponent();
  22. return null;
  23. }

打个断点看下

parseAspect的方法如下, 处理方法不难,我这里就不展开了

  1. private void parseAspect(Element aspectElement, ParserContext parserContext) {
  2. String aspectId = aspectElement.getAttribute(ID);
  3. String aspectName = aspectElement.getAttribute(REF);
  4. try {
  5. this.parseState.push(new AspectEntry(aspectId, aspectName));
  6. List<BeanDefinition> beanDefinitions = new ArrayList<>();
  7. List<BeanReference> beanReferences = new ArrayList<>();
  8. List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
  9. for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
  10. Element declareParentsElement = declareParents.get(i);
  11. beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
  12. }
  13. // We have to parse "advice" and all the advice kinds in one loop, to get the
  14. // ordering semantics right.
  15. NodeList nodeList = aspectElement.getChildNodes();
  16. boolean adviceFoundAlready = false;
  17. for (int i = 0; i < nodeList.getLength(); i++) {
  18. Node node = nodeList.item(i);
  19. if (isAdviceNode(node, parserContext)) {
  20. if (!adviceFoundAlready) {
  21. adviceFoundAlready = true;
  22. if (!StringUtils.hasText(aspectName)) {
  23. parserContext.getReaderContext().error(
  24. "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
  25. aspectElement, this.parseState.snapshot());
  26. return;
  27. }
  28. beanReferences.add(new RuntimeBeanReference(aspectName));
  29. }
  30. AbstractBeanDefinition advisorDefinition = parseAdvice(
  31. aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
  32. beanDefinitions.add(advisorDefinition);
  33. }
  34. }
  35. AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
  36. aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
  37. parserContext.pushContainingComponent(aspectComponentDefinition);
  38. List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
  39. for (Element pointcutElement : pointcuts) {
  40. parsePointcut(pointcutElement, parserContext);
  41. }
  42. parserContext.popAndRegisterContainingComponent();
  43. }
  44. finally {
  45. this.parseState.pop();
  46. }
  47. }

aspectj-autoproxy配置标签的解析

<aop:aspectj-autoproxy/>则由AspectJAutoProxyBeanDefinitionParser这个类处理的,我们看下parse 方法

  1. @Override
  2. @Nullable
  3. public BeanDefinition parse(Element element, ParserContext parserContext) {
  4. // 注册AspectJAnnotationAutoProxyCreator
  5. AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
  6. // 拓展BeanDefinition
  7. extendBeanDefinition(element, parserContext);
  8. return null;
  9. }

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法对应如下

  1. public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
  2. ParserContext parserContext, Element sourceElement) {
  3. BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
  4. parserContext.getRegistry(), parserContext.extractSource(sourceElement));
  5. useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
  6. registerComponentIfNecessary(beanDefinition, parserContext);
  7. }

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary对应如下

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

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

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

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

如下是类结构关系

它实现了两类接口:

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

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

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

postProcessBeforeInstantiation

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

  1. @Override
  2. public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
  3. Object cacheKey = getCacheKey(beanClass, beanName);
  4. if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
  5. // 如果已经在缓存中,则忽略
  6. if (this.advisedBeans.containsKey(cacheKey)) {
  7. return null;
  8. }
  9. // 是否是aop基础类?是否跳过?
  10. if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
  11. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  12. return null;
  13. }
  14. }
  15. // Create proxy here if we have a custom TargetSource.
  16. // Suppresses unnecessary default instantiation of the target bean:
  17. // The TargetSource will handle target instances in a custom fashion.
  18. TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
  19. if (targetSource != null) {
  20. if (StringUtils.hasLength(beanName)) {
  21. this.targetSourcedBeans.add(beanName);
  22. }
  23. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
  24. Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
  25. this.proxyTypes.put(cacheKey, proxy.getClass());
  26. return proxy;
  27. }
  28. return null;
  29. }

判断是否是aop基础类

是否是aop基础类的判断方法 isInfrastructureClass 如下

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

父类判断它是否是aop基础类的方法 super.isInfrastructureClass(beanClass), 本质上就是判断该类是否实现了Advice, Pointcut, Advisor或者AopInfrastructureBean接口。

  1. protected boolean isInfrastructureClass(Class<?> beanClass) {
  2. // 该类是否实现了Advice, Pointcut, Advisor或者AopInfrastructureBean接口
  3. boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
  4. Pointcut.class.isAssignableFrom(beanClass) ||
  5. Advisor.class.isAssignableFrom(beanClass) ||
  6. AopInfrastructureBean.class.isAssignableFrom(beanClass);
  7. if (retVal && logger.isTraceEnabled()) {
  8. logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
  9. }
  10. return retVal;
  11. }

是否应该跳过shouldSkip

通过断点辅助,candidateAdvisors是就是xml配置的通知是对应的

  1. @Override
  2. protected boolean shouldSkip(Class<?> beanClass, String beanName) {
  3. // TODO: Consider optimization by caching the list of the aspect names
  4. List<Advisor> candidateAdvisors = findCandidateAdvisors();
  5. for (Advisor advisor : candidateAdvisors) {
  6. if (advisor instanceof AspectJPointcutAdvisor &&
  7. ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
  8. return true;
  9. }
  10. }
  11. return super.shouldSkip(beanClass, beanName);
  12. }

切面方法转成Advisor

findCandidateAdvisors方法如下:

  1. @Override
  2. protected List<Advisor> findCandidateAdvisors() {
  3. // 在父类中找到所有的advisor:基于xml配置的<aop:before/>生成的
  4. List<Advisor> advisors = super.findCandidateAdvisors();
  5. // 为bean Factory中AspectJ切面构建advistor:通过AspectJ注解的方式生成Advisor类
  6. if (this.aspectJAdvisorsBuilder != null) {
  7. advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  8. }
  9. return advisors;
  10. }

在当前的bean Factory中通过AspectJ注解的方式生成Advisor类,buildAspectJAdvisors方法如下

  1. /**
  2. * Look for AspectJ-annotated aspect beans in the current bean factory,
  3. * and return to a list of Spring AOP Advisors representing them.
  4. * <p>Creates a Spring Advisor for each AspectJ advice method.
  5. * @return the list of {@link org.springframework.aop.Advisor} beans
  6. * @see #isEligibleBean
  7. */
  8. public List<Advisor> buildAspectJAdvisors() {
  9. List<String> aspectNames = this.aspectBeanNames;
  10. if (aspectNames == null) {
  11. synchronized (this) {
  12. aspectNames = this.aspectBeanNames;
  13. if (aspectNames == null) {
  14. List<Advisor> advisors = new ArrayList<>();
  15. aspectNames = new ArrayList<>();
  16. String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  17. this.beanFactory, Object.class, true, false);
  18. for (String beanName : beanNames) {
  19. if (!isEligibleBean(beanName)) {
  20. continue;
  21. }
  22. // We must be careful not to instantiate beans eagerly as in this case they
  23. // would be cached by the Spring container but would not have been weaved.
  24. Class<?> beanType = this.beanFactory.getType(beanName, false);
  25. if (beanType == null) {
  26. continue;
  27. }
  28. if (this.advisorFactory.isAspect(beanType)) {
  29. aspectNames.add(beanName);
  30. AspectMetadata amd = new AspectMetadata(beanType, beanName);
  31. if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
  32. MetadataAwareAspectInstanceFactory factory =
  33. new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
  34. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
  35. // 单例加到advisorsCache, 非单例加到aspectFactoryCache
  36. if (this.beanFactory.isSingleton(beanName)) {
  37. this.advisorsCache.put(beanName, classAdvisors);
  38. }
  39. else {
  40. this.aspectFactoryCache.put(beanName, factory);
  41. }
  42. advisors.addAll(classAdvisors);
  43. }
  44. else {
  45. // Per target or per this.
  46. if (this.beanFactory.isSingleton(beanName)) {
  47. throw new IllegalArgumentException("Bean with name '" + beanName +
  48. "' is a singleton, but aspect instantiation model is not singleton");
  49. }
  50. MetadataAwareAspectInstanceFactory factory =
  51. new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
  52. this.aspectFactoryCache.put(beanName, factory);
  53. // advisorFactory工厂获取advisors
  54. advisors.addAll(this.advisorFactory.getAdvisors(factory));
  55. }
  56. }
  57. }
  58. this.aspectBeanNames = aspectNames;
  59. return advisors;
  60. }
  61. }
  62. }
  63. if (aspectNames.isEmpty()) {
  64. return Collections.emptyList();
  65. }
  66. List<Advisor> advisors = new ArrayList<>();
  67. for (String aspectName : aspectNames) {
  68. List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
  69. if (cachedAdvisors != null) {
  70. advisors.addAll(cachedAdvisors);
  71. }
  72. else {
  73. MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
  74. advisors.addAll(this.advisorFactory.getAdvisors(factory));
  75. }
  76. }
  77. return advisors;
  78. }

上述方法本质上的思路是:用DCL双重锁的单例实现方式,拿到切面类里的切面方法,将其转换成advisor(并放入缓存中)。

转换的成advisor的方法是:this.advisorFactory.getAdvisors

  1. @Override
  2. public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
  3. Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  4. String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
  5. validate(aspectClass);
  6. // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
  7. // so that it will only instantiate once.
  8. MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
  9. new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
  10. List<Advisor> advisors = new ArrayList<>();
  11. for (Method method : getAdvisorMethods(aspectClass)) {
  12. // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
  13. // to getAdvisor(...) to represent the "current position" in the declared methods list.
  14. // However, since Java 7 the "current position" is not valid since the JDK no longer
  15. // returns declared methods in the order in which they are declared in the source code.
  16. // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
  17. // discovered via reflection in order to support reliable advice ordering across JVM launches.
  18. // Specifically, a value of 0 aligns with the default value used in
  19. // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
  20. Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
  21. if (advisor != null) {
  22. advisors.add(advisor);
  23. }
  24. }
  25. // If it's a per target aspect, emit the dummy instantiating aspect.
  26. if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
  27. Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
  28. advisors.add(0, instantiationAdvisor);
  29. }
  30. // Find introduction fields.
  31. for (Field field : aspectClass.getDeclaredFields()) {
  32. Advisor advisor = getDeclareParentsAdvisor(field);
  33. if (advisor != null) {
  34. advisors.add(advisor);
  35. }
  36. }
  37. return advisors;
  38. }

getAdvisor方法如下

  1. @Override
  2. @Nullable
  3. public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
  4. int declarationOrderInAspect, String aspectName) {
  5. validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
  6. AspectJExpressionPointcut expressionPointcut = getPointcut(
  7. candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
  8. if (expressionPointcut == null) {
  9. return null;
  10. }
  11. // 封装成advisor
  12. return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
  13. this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
  14. }

获取表达式的切点

获取表达式的切点的方法getPointcut如下:

  1. @Nullable
  2. private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
  3. AspectJAnnotation<?> aspectJAnnotation =
  4. AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  5. if (aspectJAnnotation == null) {
  6. return null;
  7. }
  8. AspectJExpressionPointcut ajexp =
  9. new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
  10. ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
  11. if (this.beanFactory != null) {
  12. ajexp.setBeanFactory(this.beanFactory);
  13. }
  14. return ajexp;
  15. }

AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod的方法如下

  1. private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
  2. Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
  3. /**
  4. * Find and return the first AspectJ annotation on the given method
  5. * (there <i>should</i> only be one anyway...).
  6. */
  7. @SuppressWarnings("unchecked")
  8. @Nullable
  9. protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
  10. for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
  11. AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
  12. if (foundAnnotation != null) {
  13. return foundAnnotation;
  14. }
  15. }
  16. return null;
  17. }

findAnnotation方法如下

  1. @Nullable
  2. private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
  3. A result = AnnotationUtils.findAnnotation(method, toLookFor);
  4. if (result != null) {
  5. return new AspectJAnnotation<>(result);
  6. }
  7. else {
  8. return null;
  9. }
  10. }

AnnotationUtils.findAnnotation 获取注解方法如下

  1. /**
  2. * Find a single {@link Annotation} of {@code annotationType} on the supplied
  3. * {@link Method}, traversing its super methods (i.e. from superclasses and
  4. * interfaces) if the annotation is not <em>directly present</em> on the given
  5. * method itself.
  6. * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
  7. * <p>Meta-annotations will be searched if the annotation is not
  8. * <em>directly present</em> on the method.
  9. * <p>Annotations on methods are not inherited by default, so we need to handle
  10. * this explicitly.
  11. * @param method the method to look for annotations on
  12. * @param annotationType the annotation type to look for
  13. * @return the first matching annotation, or {@code null} if not found
  14. * @see #getAnnotation(Method, Class)
  15. */
  16. @Nullable
  17. public static <A extends Annotation> A findAnnotation(Method method, @Nullable Class<A> annotationType) {
  18. if (annotationType == null) {
  19. return null;
  20. }
  21. // Shortcut: directly present on the element, with no merging needed?
  22. if (AnnotationFilter.PLAIN.matches(annotationType) ||
  23. AnnotationsScanner.hasPlainJavaAnnotationsOnly(method)) {
  24. return method.getDeclaredAnnotation(annotationType);
  25. }
  26. // Exhaustive retrieval of merged annotations...
  27. return MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
  28. .get(annotationType).withNonMergedAttributes()
  29. .synthesize(MergedAnnotation::isPresent).orElse(null);
  30. }

封装成Advisor

注:Advisor 是 advice的包装器,包含了advice及其它信息

由InstantiationModelAwarePointcutAdvisorImpl构造完成

  1. public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
  2. Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
  3. MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
  4. this.declaredPointcut = declaredPointcut;
  5. this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
  6. this.methodName = aspectJAdviceMethod.getName();
  7. this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
  8. this.aspectJAdviceMethod = aspectJAdviceMethod;
  9. this.aspectJAdvisorFactory = aspectJAdvisorFactory;
  10. this.aspectInstanceFactory = aspectInstanceFactory;
  11. this.declarationOrder = declarationOrder;
  12. this.aspectName = aspectName;
  13. if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
  14. // Static part of the pointcut is a lazy type.
  15. Pointcut preInstantiationPointcut = Pointcuts.union(
  16. aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
  17. // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
  18. // If it's not a dynamic pointcut, it may be optimized out
  19. // by the Spring AOP infrastructure after the first evaluation.
  20. this.pointcut = new PerTargetInstantiationModelPointcut(
  21. this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
  22. this.lazy = true;
  23. }
  24. else {
  25. // A singleton aspect.
  26. this.pointcut = this.declaredPointcut;
  27. this.lazy = false;
  28. this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
  29. }
  30. }

通过pointcut获取advice

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

交给aspectJAdvisorFactory获取

  1. @Override
  2. @Nullable
  3. public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
  4. MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
  5. // 获取切面类
  6. Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  7. validate(candidateAspectClass);
  8. // 获取切面注解
  9. AspectJAnnotation<?> aspectJAnnotation =
  10. AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  11. if (aspectJAnnotation == null) {
  12. return null;
  13. }
  14. // If we get here, we know we have an AspectJ method.
  15. // Check that it's an AspectJ-annotated class
  16. if (!isAspect(candidateAspectClass)) {
  17. throw new AopConfigException("Advice must be declared inside an aspect type: " +
  18. "Offending method '" + candidateAdviceMethod + "' in class [" +
  19. candidateAspectClass.getName() + "]");
  20. }
  21. if (logger.isDebugEnabled()) {
  22. logger.debug("Found AspectJ method: " + candidateAdviceMethod);
  23. }
  24. // 切面注解转换成advice
  25. AbstractAspectJAdvice springAdvice;
  26. switch (aspectJAnnotation.getAnnotationType()) {
  27. case AtPointcut: // AtPointcut忽略
  28. if (logger.isDebugEnabled()) {
  29. logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
  30. }
  31. return null;
  32. case AtAround:
  33. springAdvice = new AspectJAroundAdvice(
  34. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  35. break;
  36. case AtBefore:
  37. springAdvice = new AspectJMethodBeforeAdvice(
  38. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  39. break;
  40. case AtAfter:
  41. springAdvice = new AspectJAfterAdvice(
  42. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  43. break;
  44. case AtAfterReturning:
  45. springAdvice = new AspectJAfterReturningAdvice(
  46. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  47. AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
  48. if (StringUtils.hasText(afterReturningAnnotation.returning())) {
  49. springAdvice.setReturningName(afterReturningAnnotation.returning());
  50. }
  51. break;
  52. case AtAfterThrowing:
  53. springAdvice = new AspectJAfterThrowingAdvice(
  54. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  55. AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
  56. if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
  57. springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
  58. }
  59. break;
  60. default:
  61. throw new UnsupportedOperationException(
  62. "Unsupported advice type on method: " + candidateAdviceMethod);
  63. }
  64. // 最后将其它切面信息配置到advice
  65. springAdvice.setAspectName(aspectName);
  66. springAdvice.setDeclarationOrder(declarationOrder);
  67. String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
  68. if (argNames != null) {
  69. springAdvice.setArgumentNamesFromStringArray(argNames);
  70. }
  71. springAdvice.calculateArgumentBindings();
  72. return springAdvice;
  73. }

小结

回头看,主要是处理使用了@Aspect注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor的过程。

postProcessAfterInitialization

有了Adisor, 注入到合适的位置并交给代理(cglib和jdk)实现了。

  1. /**
  2. * Create a proxy with the configured interceptors if the bean is
  3. * identified as one to proxy by the subclass.
  4. * @see #getAdvicesAndAdvisorsForBean
  5. */
  6. @Override
  7. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  8. if (bean != null) {
  9. Object cacheKey = getCacheKey(bean.getClass(), beanName);
  10. if (this.earlyProxyReferences.remove(cacheKey) != bean) {
  11. return wrapIfNecessary(bean, beanName, cacheKey);
  12. }
  13. }
  14. return bean;
  15. }

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

总结

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

  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处理请求的过程的源码解析。

Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现的更多相关文章

  1. Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建

    上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor).本文在此基 ...

  2. Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现

    我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理.@pdai Spring框架系列 ...

  3. Spring框架系列(12) - Spring AOP实现原理详解之JDK代理实现

    上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分.@pdai Spring框架系列(12) - Spring AOP实现原理详解 ...

  4. Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计

    在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ...

  5. Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程

    上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...

  6. Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...

  7. Spring框架系列(2) - Spring简单例子引入Spring要点

    上文中我们简单介绍了Spring和Spring Framework的组件,那么这些Spring Framework组件是如何配合工作的呢?本文主要承接上文,向你展示Spring Framework组件 ...

  8. Spring Aop底层原理详解

    Spring Aop底层原理详解(来源于csdn:https://blog.csdn.net/baomw)

  9. Spring源码剖析7:AOP实现原理详解

    前言 前面写了六篇文章详细地分析了Spring Bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析.为了探究AOP实现原理,首先定义几个类,一个Dao接口: pub ...

随机推荐

  1. angular.js中指令compile与link原理剖析

    在angularJs应用启动之前,它们是以HTML文本形式存在文本编辑器当中.应用启动会进行编译和链接,作用域会同HTML进行绑定.这个过程包含了两个阶段! 编译阶段 在编译的阶段,angularJs ...

  2. PyTorch 广播机制

    PyTorch 广播机制 定义 PyTorch的tensor参数可以自动扩展其大小.一般的是小一点的会变大,来满足运算需求. 规则 满足一下情况的tensor是可以广播的. 至少有一个维度 两个ten ...

  3. 【面试普通人VS高手系列】b树和b+树的理解

    数据结构与算法问题,困扰了无数的小伙伴. 很多小伙伴对数据结构与算法的认知有一个误区,认为工作中没有用到,为什么面试要问,问了能解决实际问题? 图灵奖获得者: Niklaus Wirth 说过: 程序 ...

  4. [AcWing 776] 字符串移位包含问题

    点击查看代码 #include<iostream> #include<algorithm> using namespace std; string a, b; int main ...

  5. 开发一个不需要重写成Hive QL的大数据SQL引擎

    摘要:开发一款能支持标准数据库SQL的大数据仓库引擎,让那些在Oracle上运行良好的SQL可以直接运行在Hadoop上,而不需要重写成Hive QL. 本文分享自华为云社区<​​​​​​​​​ ...

  6. 【CSAPP】Performance Lab 实验笔记

    perflab这节的任务是利用书中知识,来对图像处理中的Rotate和Smooth操作函数进行优化.这次没对上电波,觉得学了一堆屠龙之技.于我个人理解,现在计算机配置比以前高多了,连SWAP分区都几近 ...

  7. 交换机POE技术知识大全

    公众号关注 「开源Linux」 回复「学习」,有我为您特别筛选的学习资料~ 一个典型的以太网供电系统,在配线柜里保留以太网交换机设备,用一个带电源供电集线器(Midspan HUB)给局域网的双绞线提 ...

  8. .NET混合开发解决方案8 WinForm程序中通过设置固定版本运行时的BrowserExecutableFolder属性集成WebView2控件

    系列目录     [已更新最新开发文章,点击查看详细] 在我的博客<.NET混合开发解决方案7 WinForm程序中通过NuGet管理器引用集成WebView2控件>中介绍了WinForm ...

  9. 归约与分组 - 读《Java 8实战》

    区分Collection,Collector和collect 代码中用到的类与方法用红框标出,可从git库中查看 收集器用作高级归约 // 按货币对交易进行分组 Map<Currency, Li ...

  10. 12┃音视频直播系统之 WebRTC 实现1对1直播系统实战

    一.搭建 Web 服务器 前面我们已经实现过,但是没有详细说HTTPS服务 首先需要引入了 express 库,它的功能非常强大,用它来实现 Web 服务器非常方便 同时还需要引入 HTTPS 服务, ...