前言

在上一篇博文中我们说到了通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,那么这个类究竟做了什么工作从而完成AOP的操作呢?首先我们看一下AnnotationAwareAspectJAutoProxyCreator的类图结构,如图:

AOP的源码解析操作入口

  1. UML类图中我们看到`AnnotationAwareAspectJAutoProxyCreator`这个类实现了`BeanPostProcessor`接口,而实现这个`BeanPostProcessor`后,当Spring加载这个Bean时会在实例化之前调用器`postProcessorAfterIntialization`方法,而我们就从这里进行分析AOP的逻辑
  • 首先我们先看一下它父类AbstractAutoProxyCreatorpostProcessorIntialization方法

  • 看源码(具体实现在AbstractAutoProxyCreator.class)

  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. // 根据bean的class 和 name构建出一个key 格式:beanClassName_beanName
  10. Object cacheKey = getCacheKey(bean.getClass(), beanName);
  11. if (this.earlyProxyReferences.remove(cacheKey) != bean) {
  12. // 如果它适合被代理,则需要指定封装bean
  13. return wrapIfNecessary(bean, beanName, cacheKey);
  14. }
  15. }
  16. return bean;
  17. }

在上面代码中用到了方法wrapIfNecessary,进入到该函数方法的内部:

  • 看源码(具体实现在AbstractAutoProxyCreator.class)
  1. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  2. // 如果已经处理过
  3. if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
  4. return bean;
  5. }
  6. // 无需增强
  7. if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
  8. return bean;
  9. }
  10. // 给定的bean类是否是一个基础设施类,基础设施类不应该被代理,或者配置了指定的bean不需要代理
  11. if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
  12. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  13. return bean;
  14. }
  15. // 如果存在增强方法则创建
  16. // Create proxy if we have advice.
  17. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  18. if (specificInterceptors != DO_NOT_PROXY) {
  19. // 如果获取到了增强则需要针对增强进行代理
  20. this.advisedBeans.put(cacheKey, Boolean.TRUE);
  21. // 创建代理
  22. Object proxy = createProxy(
  23. bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  24. this.proxyTypes.put(cacheKey, proxy.getClass());
  25. return proxy;
  26. }
  27. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  28. return bean;
  29. }
  1. 从上面的函数中我们可以大概看出代理的创建过程的一个雏形。当然真正的开始之前还需要一些个判断,比如是否已经处理过或者是 是否需要跳过的bean,而真正创建代理的代码是在`getAdvicesAndAdvisorsForBean`函数开始的。

** 创建代理需要两个步骤:**

  1. 获取增强方法或增强器;
  2. 根据获取的增强来进行代理。

上述两个步骤其中逻辑是十分复杂的,首先来看看获取增强方法的逻辑实现。获取增强的方法getAdvicesAndAdvisorsForBean是在AbstractAdvisorAuroProxyCreator中实现的,代码如下:

  • 看源码(具体实现在AbstractAdvisorAuroProxyCreator.class)
  1. @Override
  2. @Nullable
  3. protected Object[] getAdvicesAndAdvisorsForBean(
  4. Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
  5. List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  6. if (advisors.isEmpty()) {
  7. return DO_NOT_PROXY;
  8. }
  9. return advisors.toArray();
  10. }
  • 源码分析

主要查看上述函数体内的findEligibleAdvisor方法。进入该方法实现也在AbstractAdvisorAuroProxyCreator.class

  • 看源码(具体实现在AbstractAdvisorAutoProxyCreator.class)
  1. protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  2. List<Advisor> candidateAdvisors = findCandidateAdvisors();
  3. List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  4. extendAdvisors(eligibleAdvisors);
  5. if (!eligibleAdvisors.isEmpty()) {
  6. eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  7. }
  8. return eligibleAdvisors;
  9. }
  • 源码分析

通过findEligbleAdvisor的具体实现我们看到,对于指定bean的增强方法的获取包含了两个步骤:

  1. 获取所有增强,
  2. 寻找所有增强中 对于bean的增强并应用(也就是寻找匹配bean的增强器)。

函数中的findCandidateAdvisorsfindAdvisorsThatCanApply便是做了这两件事

当然如果这个方法没有找到增强器,getAdvicesAndAdvisorsForBean就会返回一个DO_NOT_PROXY,DO_NOT_PROXY时已经定义好的null

获取增强器

从一开始我们分析的就是基于注解进行的AOP,所以对于findidateAdvisors的实现是由AnnotationAwareAspectJAutoProxyCreator类的findCandidateAdvisors方法完成的。

  • 看源码(具体实现在AnnotationAwareAspectJAutoProxyCreator.class)
  1. @Override
  2. protected List<Advisor> findCandidateAdvisors() {
  3. // Add all the Spring advisors found according to superclass rules.
  4. // 当使用注解方式配置AOP的时候并不是对xml配置文件的支持进行了丢弃
  5. // 在这里调用父类加载配置文件中的AOP声明
  6. List<Advisor> advisors = super.findCandidateAdvisors();
  7. // Build Advisors for all AspectJ aspects in the bean factory.
  8. if (this.aspectJAdvisorsBuilder != null) {
  9. advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  10. }
  11. return advisors;
  12. }
  • 源码解析:

首先我们先看一下AnnotationAwareAspectJAutoProxyCreator.class这个类的UML,

在上图中我们看到AnnotationAwareAspectJAutoProxyCreator间接继承了AbstractAdvisorsAutoProxyCreator,在实现获取增强方法中保留了父类的获取配置文件中定义的增强,是由List<Advisor> advisors = super.findCandidateAdvisors();实现;

此外同时还添加了获取Bean的注解增强的功能,是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()这个方法实现的

Spring获取增强器(增强方法)的解析思路大致如下:

  1. 获取所有的beanName,这一步骤中所有的beanFactory中注册的Bean都会被提取出来。
  2. 遍历所有的beanName,并找出使用**@Aspect注解声明的类,并进行进一步处理。
  3. 对于标记Aspect注解的类进行增强器的提取。
  4. 将提取结果加入缓存

接下来我们分析一下以上步骤的实现,首先

  • this.aspectJAdvisorsBuilder.buildAspectJAdvisors()源码的实现(具体实现在BeanFactoryAspectJAdvisorsBuilder.class)
  1. public List<Advisor> buildAspectJAdvisors() {
  2. List<String> aspectNames = this.aspectBeanNames;
  3. if (aspectNames == null) {
  4. synchronized (this) {
  5. aspectNames = this.aspectBeanNames;
  6. if (aspectNames == null) {
  7. List<Advisor> advisors = new ArrayList<>();
  8. aspectNames = new ArrayList<>();
  9. // 获取所有的beanName
  10. String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  11. this.beanFactory, Object.class, true, false);
  12. // 循环所有的beanName获取 获取声明AspectJ的类,找出对应的增强方法
  13. for (String beanName : beanNames) {
  14. // 不合法的bean 则略过,由子类定义规则返回true
  15. if (!isEligibleBean(beanName)) {
  16. continue;
  17. }
  18. // We must be careful not to instantiate beans eagerly as in this case they
  19. // would be cached by the Spring container but would not have been weaved.
  20. // 获取对应的bean Class类型
  21. Class<?> beanType = this.beanFactory.getType(beanName, false);
  22. if (beanType == null) {
  23. continue;
  24. }
  25. if (this.advisorFactory.isAspect(beanType)) {
  26. aspectNames.add(beanName);
  27. AspectMetadata amd = new AspectMetadata(beanType, beanName);
  28. if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
  29. MetadataAwareAspectInstanceFactory factory =
  30. new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
  31. // 解析标记AspectJ注解的增强方法
  32. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
  33. if (this.beanFactory.isSingleton(beanName)) {
  34. // 将增强器加入缓存 下次可以直接取
  35. this.advisorsCache.put(beanName, classAdvisors);
  36. }
  37. else {
  38. this.aspectFactoryCache.put(beanName, factory);
  39. }
  40. advisors.addAll(classAdvisors);
  41. }
  42. else {
  43. // Per target or per this.
  44. if (this.beanFactory.isSingleton(beanName)) {
  45. throw new IllegalArgumentException("Bean with name '" + beanName +
  46. "' is a singleton, but aspect instantiation model is not singleton");
  47. }
  48. MetadataAwareAspectInstanceFactory factory =
  49. new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
  50. this.aspectFactoryCache.put(beanName, factory);
  51. advisors.addAll(this.advisorFactory.getAdvisors(factory));
  52. }
  53. }
  54. }
  55. this.aspectBeanNames = aspectNames;
  56. return advisors;
  57. }
  58. }
  59. }
  60. if (aspectNames.isEmpty()) {
  61. return Collections.emptyList();
  62. }
  63. // 记录在缓存中
  64. List<Advisor> advisors = new ArrayList<>();
  65. for (String aspectName : aspectNames) {
  66. List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
  67. if (cachedAdvisors != null) {
  68. advisors.addAll(cachedAdvisors);
  69. }
  70. else {
  71. MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
  72. advisors.addAll(this.advisorFactory.getAdvisors(factory));
  73. }
  74. }
  75. return advisors;
  76. }
  1. 执行到此,Spring就完成了Advisor的提取,在上面的步骤中**最繁杂最重要**的就是增强**器的获取**,而这一步又交给了`getAdvisors`方法去实现的。(`this.advisorFactory.getAdvisors(factory);`)
  • 首先看this.advisorFactory.isAspect(beanType)源码(具体实现在AbstractAspectJAdvisorFactory.class)
  1. @Override
  2. public boolean isAspect(Class<?> clazz) {
  3. return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
  4. }
  5. private boolean hasAspectAnnotation(Class<?> clazz) {
  6. return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
  7. }

紧接着再查看一下findAnnotation方法:

  1. @Nullable
  2. public static <A extends Annotation> A findAnnotation(Class<?> clazz, @Nullable Class<A> annotationType) {
  3. if (annotationType == null) {
  4. return null;
  5. }
  6. // Shortcut: directly present on the element, with no merging needed?
  7. if (AnnotationFilter.PLAIN.matches(annotationType) ||
  8. AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
  9. // 判断此Class 是否存在Aspect.class注解
  10. A annotation = clazz.getDeclaredAnnotation(annotationType);
  11. if (annotation != null) {
  12. return annotation;
  13. }
  14. // For backwards compatibility, perform a superclass search with plain annotations
  15. // even if not marked as @Inherited: e.g. a findAnnotation search for @Deprecated
  16. Class<?> superclass = clazz.getSuperclass();
  17. if (superclass == null || superclass == Object.class) {
  18. return null;
  19. }
  20. return findAnnotation(superclass, annotationType);
  21. }
  22. // Exhaustive retrieval of merged annotations...
  23. return MergedAnnotations.from(clazz, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
  24. .get(annotationType).withNonMergedAttributes()
  25. .synthesize(MergedAnnotation::isPresent).orElse(null);
  26. }

这里如果bean存在Aspect.class注解,那么就可以获取此bean的增强器了,接下来我们回到BeanFactoryAspectJAdvisorsBuilder类中查看this.advisorFactory.getAdvisors(factory);方法。

  • 看源码(具体实现在ReflectiveAspectJAdvisorFactory.class)
  1. @Override
  2. public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
  3. // 获取标记AspectJ的类
  4. Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  5. // 获取标记AspectJ的name
  6. String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
  7. validate(aspectClass);
  8. // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
  9. // so that it will only instantiate once.
  10. MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
  11. new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
  12. List<Advisor> advisors = new ArrayList<>();
  13. // 对于aspect class的每一个带有注解的方法进行循环(除了@Pointcut注解的方法除外),取得Advisor,并添加到集合里
  14. // 这里应该取到的是Advice,然后取得我们自定义的切面类中的PointCut,组合成Advisor
  15. for (Method method : getAdvisorMethods(aspectClass)) {
  16. // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
  17. // to getAdvisor(...) to represent the "current position" in the declared methods list.
  18. // However, since Java 7 the "current position" is not valid since the JDK no longer
  19. // returns declared methods in the order in which they are declared in the source code.
  20. // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
  21. // discovered via reflection in order to support reliable advice ordering across JVM launches.
  22. // Specifically, a value of 0 aligns with the default value used in
  23. // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
  24. // 将类中的方法封装成Advisor
  25. Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
  26. if (advisor != null) {
  27. advisors.add(advisor);
  28. }
  29. }
  30. // If it's a per target aspect, emit the dummy instantiating aspect.
  31. if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
  32. Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
  33. advisors.add(0, instantiationAdvisor);
  34. }
  35. // Find introduction fields.
  36. for (Field field : aspectClass.getDeclaredFields()) {
  37. Advisor advisor = getDeclareParentsAdvisor(field);
  38. if (advisor != null) {
  39. advisors.add(advisor);
  40. }
  41. }
  42. return advisors;
  43. }
普通增强器的获取

普通增强其的获取逻辑通过getAdvisor方法实现,实现步骤包括对切点的注解的获取以及根据注解信息生成增强。

首先我们看一下 getAdvisorMethods(aspectClass)这个方法,它很巧妙的使用接口定义一个匿名回调,把带有注解的Method都取出来,放到集合里。

  • 看源码
  1. private List<Method> getAdvisorMethods(Class<?> aspectClass) {
  2. List<Method> methods = new ArrayList<>();
  3. ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
  4. if (methods.size() > 1) {
  5. methods.sort(adviceMethodComparator);
  6. }
  7. return methods;
  8. }

然后在看一下函数体内的doWithMethods方法 具体实现在ReflectionUtils

  1. public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
  2. // Keep backing up the inheritance hierarchy.
  3. Method[] methods = getDeclaredMethods(clazz, false);
  4. for (Method method : methods) {
  5. if (mf != null && !mf.matches(method)) {
  6. continue;
  7. }
  8. try {
  9. mc.doWith(method);
  10. }
  11. catch (IllegalAccessException ex) {
  12. throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
  13. }
  14. }
  15. if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
  16. doWithMethods(clazz.getSuperclass(), mc, mf);
  17. }
  18. else if (clazz.isInterface()) {
  19. for (Class<?> superIfc : clazz.getInterfaces()) {
  20. doWithMethods(superIfc, mc, mf);
  21. }
  22. }
  23. }

然后我们在回到ReflectiveAspectJAdvisorFactory.class类中获取普通增强器的getAdvisor方法

  • 看源码(具体实现在ReflectiveAspectJAdvisorFactory.class)
  1. @Override
  2. @Nullable
  3. public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
  4. int declarationOrderInAspect, String aspectName) {
  5. validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
  6. // 获取Pointcut信息 主要是获取Pointcut表达式
  7. // 把Method对象也传进去的目的是,比较Method对象上的注解,是不是下面的注解的其中的一个,
  8. // 如果不是返回null;如果是就把Pointcut内容包装返回
  9. AspectJExpressionPointcut expressionPointcut = getPointcut(
  10. candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
  11. if (expressionPointcut == null) {
  12. return null;
  13. }
  14. // 根据Pointcut信息生成增强器
  15. return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
  16. this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
  17. }
切点信息的获取

所谓获取切点信息就是指注解的表达式信息的获取,如@Before("test()")。

  • 看源码(具体在ReflectiveAspectJAdvisorFactory.class)
  1. @Nullable
  2. private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
  3. // 获取方法上的注解,比较Method对象上的注解是不是下面其中的一个,如果不是返回null
  4. // 被比较的注解:Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
  5. AspectJAnnotation<?> aspectJAnnotation =
  6. AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  7. if (aspectJAnnotation == null) {
  8. return null;
  9. }
  10. // 使用AspectJExpressionPointcut实例封装获取的信息
  11. AspectJExpressionPointcut ajexp =
  12. new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
  13. // 提取到注解中的表达式并设置进去
  14. ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
  15. if (this.beanFactory != null) {
  16. ajexp.setBeanFactory(this.beanFactory);
  17. }
  18. return ajexp;
  19. }

我们再看一下上面使用到的findAspectJAnnotationOnMethod方法的实现

  • 看源码(具体是现在AbstractAspectJAdvisorFactory.class)
  1. @Nullable
  2. protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
  3. for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
  4. AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
  5. if (foundAnnotation != null) {
  6. return foundAnnotation;
  7. }
  8. }
  9. return null;
  10. }

小插曲:注意一下上面的ASPECTJ_ANNOTATION_CLASSES变量,它设置了查找的注解类:

  • 源码
  1. private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
  2. Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

再次回到findAspectJAnnotationOnMethod方法的实现,里面使用了findAnnotation方法,跟踪该方法

  • 看源码(具体实现在AbstractAspectAdvisorFacrory.class)
  1. /**
  2. * 获取指定方法上的注解 并使用AspectAnnotation进行封装
  3. * @param method
  4. * @param toLookFor
  5. * @param <A>
  6. * @return
  7. */
  8. @Nullable
  9. private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
  10. A result = AnnotationUtils.findAnnotation(method, toLookFor);
  11. if (result != null) {
  12. return new AspectJAnnotation<>(result);
  13. }
  14. else {
  15. return null;
  16. }
  17. }

此方法的功能是获取指定方法上的注解并使用AspectJAnnotation封装。

根据切点信息获取增强类

所有的增强都由Advisor实现类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. // 初始化Advice
  29. this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
  30. }
  31. }
  1. 通过对上面的构造函数的分析,发现封装过程只是简单的将信息封装在类的实例中,所有的信息都是单纯的复制。在实例初始化的工程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如`@Before("test()")``@After("test()")`标签的不同就是增强器的位置不同,所以需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的增强器就是在`instantiateAdvice`函数中实现的,继续跟踪源码:
  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. }
  1. 接下来再继续跟踪getAdvice函数的具体实现
  • 看源码(具体实现在ReflectiveAspectJAdvisorFactory.class)
  1. @Override
  2. @Nullable
  3. public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
  4. MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
  5. Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  6. validate(candidateAspectClass);
  7. AspectJAnnotation<?> aspectJAnnotation =
  8. AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  9. if (aspectJAnnotation == null) {
  10. return null;
  11. }
  12. // If we get here, we know we have an AspectJ method.
  13. // Check that it's an AspectJ-annotated class
  14. if (!isAspect(candidateAspectClass)) {
  15. throw new AopConfigException("Advice must be declared inside an aspect type: " +
  16. "Offending method '" + candidateAdviceMethod + "' in class [" +
  17. candidateAspectClass.getName() + "]");
  18. }
  19. if (logger.isDebugEnabled()) {
  20. logger.debug("Found AspectJ method: " + candidateAdviceMethod);
  21. }
  22. AbstractAspectJAdvice springAdvice;
  23. // 根据不同的注解类型封装不同的增强器
  24. switch (aspectJAnnotation.getAnnotationType()) {
  25. case AtPointcut:
  26. if (logger.isDebugEnabled()) {
  27. logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
  28. }
  29. return null;
  30. case AtAround:
  31. springAdvice = new AspectJAroundAdvice(
  32. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  33. break;
  34. case AtBefore:
  35. springAdvice = new AspectJMethodBeforeAdvice(
  36. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  37. break;
  38. case AtAfter:
  39. springAdvice = new AspectJAfterAdvice(
  40. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  41. break;
  42. case AtAfterReturning:
  43. springAdvice = new AspectJAfterReturningAdvice(
  44. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  45. AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
  46. if (StringUtils.hasText(afterReturningAnnotation.returning())) {
  47. springAdvice.setReturningName(afterReturningAnnotation.returning());
  48. }
  49. break;
  50. case AtAfterThrowing:
  51. springAdvice = new AspectJAfterThrowingAdvice(
  52. candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
  53. AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
  54. if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
  55. springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
  56. }
  57. break;
  58. default:
  59. throw new UnsupportedOperationException(
  60. "Unsupported advice type on method: " + candidateAdviceMethod);
  61. }
  62. // Now to configure the advice...
  63. springAdvice.setAspectName(aspectName);
  64. springAdvice.setDeclarationOrder(declarationOrder);
  65. String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
  66. if (argNames != null) {
  67. springAdvice.setArgumentNamesFromStringArray(argNames);
  68. }
  69. springAdvice.calculateArgumentBindings();
  70. return springAdvice;
  71. }
前置增强

从上面的函数中我们看到,Spring会根据不同的注解生成不同的增强器,具体表现在了switch (aspectJAnnotation.getAnnotationType()),根据不同的类型来生成。例如在AtBefore会对应AspectJMethodBeforeAdvice,早AspectJMethodBeforeAdvice中完成了增强逻辑,

  1. 并且这里的**AspectJMethodBeforeAdvice**最后被适配器封装成**MethodBeforeAdviceInterceptor**,

如何被封装的 这有机再在分析。

我们先看一下MethodBeforeAdviceInterceptor的代码

  • 看源码
  1. public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
  2. private final MethodBeforeAdvice advice;
  3. /**
  4. * Create a new MethodBeforeAdviceInterceptor for the given advice.
  5. * @param advice the MethodBeforeAdvice to wrap
  6. */
  7. public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
  8. Assert.notNull(advice, "Advice must not be null");
  9. this.advice = advice;
  10. }
  11. @Override
  12. @Nullable
  13. public Object invoke(MethodInvocation mi) throws Throwable {
  14. this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
  15. return mi.proceed();
  16. }
  17. }

其中上述代码的MethodBeforeAdvice代表的前置增强的AspectJMethodBeforeAdvice,根据before方法来到这个类。

  • 看源码(具体实现在AspectJMethodBeforeAdvice.java)
  1. @Override
  2. public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
  3. // 直接调用增强方法
  4. invokeAdviceMethod(getJoinPointMatch(), null, null);
  5. }

继续跟踪函数体内的invokeAdviceMethod方法

  • 看源码(具体实现在AbstractAspectJAdvice.java)
  1. protected Object invokeAdviceMethod(
  2. @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
  3. throws Throwable {
  4. return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
  5. }

接着继续根据函数体内的invokeAdviceMethodWithGivenArgs方法,

  • 看源码(具体实现在AbstractAspectJAdvice.java)
  1. protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
  2. Object[] actualArgs = args;
  3. if (this.aspectJAdviceMethod.getParameterCount() == 0) {
  4. actualArgs = null;
  5. }
  6. try {
  7. ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
  8. // 通过反射调用AspectJ注解类中的增强方法
  9. return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
  10. }
  11. catch (IllegalArgumentException ex) {
  12. throw new AopInvocationException("Mismatch on arguments to advice method [" +
  13. this.aspectJAdviceMethod + "]; pointcut expression [" +
  14. this.pointcut.getPointcutExpression() + "]", ex);
  15. }
  16. catch (InvocationTargetException ex) {
  17. throw ex.getTargetException();
  18. }
  19. }

invokeAdviceMethodWithGivenArgs方法中的aspectJAdviceMethod正是对前置增强的方法,在这里实现了调用。

简单总结

前置通知的大致过程是在拦截器链中放置MethodBeforeAdviceInterceptor,而在MethodBeforeAdvivceInterceptor中又放置了AspectJMethodBeforeAdvice,并在调用invoke时首先串联调用。

后置增强

相比前置增强略有不同,后置增强没有提供中间的类,而是直接在拦截器中使用过了中间的AspectJAfterAdvice,也就是直接实现了MethodInterceptor

  • 看源码(AspectJAfterAdvice.java)
  1. public class AspectJAfterAdvice extends AbstractAspectJAdvice
  2. implements MethodInterceptor, AfterAdvice, Serializable {
  3. public AspectJAfterAdvice(
  4. Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
  5. super(aspectJBeforeAdviceMethod, pointcut, aif);
  6. }
  7. @Override
  8. @Nullable
  9. public Object invoke(MethodInvocation mi) throws Throwable {
  10. try {
  11. return mi.proceed();
  12. }
  13. finally {
  14. // 激活增强方法
  15. invokeAdviceMethod(getJoinPointMatch(), null, null);
  16. }
  17. }
  18. @Override
  19. public boolean isBeforeAdvice() {
  20. return false;
  21. }
  22. @Override
  23. public boolean isAfterAdvice() {
  24. return true;
  25. }
  26. }

其他的几个增强器,下次具体来看

寻找匹配的增强器
  1. 前面的函数中已经完成了所有增强器的解析,也就是讲解完了关于`findCandidateAdvisors`方法;但是对于所有增强器来讲,并不一定都适用于当前的bean,还要取出适合的增强器,也就是满足我们配置的通配符的增强器,具体实现在`findAdvisorsThatCanAply`中,我们需要回到最初的**AbstractAdvisorAuroProxyCreator**类中,然后进入到findEligibleAdvisors函数内的**findAdvisorsThatCanAply**方法的实现:
  • 看源码(AbstractAdvisorAuroProxyCreator.java)
  1. protected List<Advisor> findAdvisorsThatCanApply(
  2. List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
  3. ProxyCreationContext.setCurrentProxiedBeanName(beanName);
  4. try {
  5. // 过滤已经得到的advisors
  6. return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
  7. }
  8. finally {
  9. ProxyCreationContext.setCurrentProxiedBeanName(null);
  10. }
  11. }

继续跟踪findAdvisorsThatCanApply方法:

  • 看源码(AOPUtils.java)
  1. public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
  2. if (candidateAdvisors.isEmpty()) {
  3. return candidateAdvisors;
  4. }
  5. List<Advisor> eligibleAdvisors = new ArrayList<>();
  6. // 首先处理引介增强
  7. /*
  8. * 引介增强是一种特殊的增强,其它的增强是方法级别的增强,即只能在方法前或方法后添加增强。
  9. * 而引介增强则不是添加到方法上的增强, 而是添加到类方法级别的增强,即可以为目标类动态实现某个接口,
  10. * 或者动态添加某些方法。我们通过下面的事例演示引介增强的使用
  11. */
  12. for (Advisor candidate : candidateAdvisors) {
  13. if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
  14. eligibleAdvisors.add(candidate);
  15. }
  16. }
  17. boolean hasIntroductions = !eligibleAdvisors.isEmpty();
  18. for (Advisor candidate : candidateAdvisors) {
  19. if (candidate instanceof IntroductionAdvisor) {
  20. // already processed
  21. continue;
  22. }
  23. // 对于普通bean的 进行处理
  24. if (canApply(candidate, clazz, hasIntroductions)) {
  25. eligibleAdvisors.add(candidate);
  26. }
  27. }
  28. return eligibleAdvisors;
  29. }

findAdvisorsThatCanApply函数的主要功能时寻找增强器中适用于当前class的增强器。引介增强普通增强的处理是不一样的,所以分开处理。而对于真正的匹配在canApply中实现。

接着跟踪canApply方法

  • 看源码(AopUtils.java)
  1. public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
  2. Assert.notNull(pc, "Pointcut must not be null");
  3. // 通过Pointcut的条件判断此类是否匹配
  4. if (!pc.getClassFilter().matches(targetClass)) {
  5. return false;
  6. }
  7. MethodMatcher methodMatcher = pc.getMethodMatcher();
  8. if (methodMatcher == MethodMatcher.TRUE) {
  9. // No need to iterate the methods if we're matching any method anyway...
  10. return true;
  11. }
  12. IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
  13. if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
  14. introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
  15. }
  16. Set<Class<?>> classes = new LinkedHashSet<>();
  17. if (!Proxy.isProxyClass(targetClass)) {
  18. classes.add(ClassUtils.getUserClass(targetClass));
  19. }
  20. classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
  21. for (Class<?> clazz : classes) {
  22. // 反射获取类中所有的方法
  23. Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
  24. for (Method method : methods) {
  25. // 根据匹配原则判断该方法是否能匹配Pointcut中的规则,如果有一个方法匹配则返回true
  26. if (introductionAwareMethodMatcher != null ?
  27. introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
  28. methodMatcher.matches(method, targetClass)) {
  29. return true;
  30. }
  31. }
  32. }
  33. return false;
  34. }
  • 源码分析

首先会判断bean是否满足切点的规则,如果能满足,则获取bean的所有方法,判断是否有方法能够匹配规则,有方法匹配规则就代表Advisor能作用于该bean,该方法就会返回true,然后findAdvisorsThatCanApply函数就会将Advisor加入到eligibleAdvisors中。

最后我们以注解的规则来看一下bean的method是怎样匹配Pointcut中的规则的
  • 看源码(AnnotationMethodMatcher.java)
  1. @Override
  2. public boolean matches(Method method, Class<?> targetClass) {
  3. if (matchesMethod(method)) {
  4. return true;
  5. }
  6. // Proxy classes never have annotations on their redeclared methods.
  7. if (Proxy.isProxyClass(targetClass)) {
  8. return false;
  9. }
  10. // The method may be on an interface, so let's check on the target class as well.
  11. Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
  12. return (specificMethod != method && matchesMethod(specificMethod));
  13. }
  14. private boolean matchesMethod(Method method) {
  15. // 可以看出判断该Advisor是否使用于bean中的method,只需看method上是否有Advisor的注解
  16. return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) :
  17. method.isAnnotationPresent(this.annotationType));
  18. }

至此:在后置处理器中找到了所有匹配Bean中的增强器,

Spring源码之创建AOP代理之增强器的获取的更多相关文章

  1. spring源码 — 三、AOP代理生成

    AOP代理生成 AOP就是面向切面编程,主要作用就是抽取公共代码,无侵入的增强现有类的功能.从一个简单的spring AOP配置开始: <?xml version="1.0" ...

  2. AOP源码解析之二-创建AOP代理前传,获取AOP信息

    AOP源码解析之二-创建AOP代理前传,获取AOP信息. 上篇文章对AOP的基本概念说清楚了,那么接下来的AOP还剩下两个大的步骤获取定义的AOP信息,生成代理对象扔到beanFactory中. 本篇 ...

  3. Spring源码分析之AOP从解析到调用

    正文: 在上一篇,我们对IOC核心部分流程已经分析完毕,相信小伙伴们有所收获,从这一篇开始,我们将会踏上新的旅程,即Spring的另一核心:AOP! 首先,为了让大家能更有效的理解AOP,先带大家过一 ...

  4. Spring源码情操陶冶-AOP之Advice通知类解析与使用

    阅读本文请先稍微浏览下上篇文章Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器,本文则对aop模式的通知类作简单的分析 入口 根据前文讲解,我们知道通知类的 ...

  5. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  6. Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器

    aop-Aspect Oriented Programming,面向切面编程.根据百度百科的解释,其通过预编译方式和运行期动态代理实现程序功能的一种技术.主要目的是为了程序间的解耦,常用于日志记录.事 ...

  7. spring源码解析之AOP原理

    一.准备工作 在这里我先简单记录下如何实现一个aop: AOP:[动态代理] 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式: 1.导入aop模块:Spring AOP:(s ...

  8. spring源码学习之AOP(二)

    接着上一篇中的内容! 3.创建代理 在获取了所有的bean对应的增强器之后,便可以进行代理的创建了org.springframework.aop.framework.autoproxy包下的Abstr ...

  9. spring源码学习之AOP(一)

    继续源码学习,看了spring中基础的容器和AOP感觉自己也没有什么长进,哈哈,我也不知道到底有用没有,这可能是培养自己的一种精神吧,不管那么多,继续学习!AOP中 AOP中几个重要的概念:(1)Ad ...

随机推荐

  1. 深入浅出Mybatis系列(九)---缓存

    MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存. 1.默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启. 2.二级缓存需要手动开启和配置,他是基于namesp ...

  2. Spring源码解析之ConfigurationClassPostProcessor(三)

    在上一章笔者介绍了ConfigurationClassParser.doProcessConfigurationClass(...)方法,在这个方法里调用了processImports(...)方法处 ...

  3. linux备份恢复命令

    dump 发行版不自带,需要 yum 或 apt 安装.安装时 restore 也会自动安装. 支持分区和增量备份(仅支持分区增量,目录备份不支持增量).(第一次完全备份,第二次及以后只备份增加和修改 ...

  4. “ShardingCore”是如何针对分表下的分页进行优化的

    分表情况下的分页如何优化 首先还是要给自己的开原框架打个广告 sharding-core 针对efcore 2+版本的分表组件,首先我们来快速回顾下目前市面上分表下针对分页常见的集中解决方案 分表解决 ...

  5. kubernetes 安装 ingress controller

    文章链接 ingress-nginx ingress 官方网站 ingress 仓库地址 ingress-nginx v1.0 最新版本 v1.0 适用于 Kubernetes 版本 v1.19+ ( ...

  6. Merchant

      \(get\)二分新用法.   每道题都有答案范围提示,以前只是以为是用来提示用什么类型输出的.   从来没想过直接用它来二分.   这道题真的刷新了我的认知啊......   整道题的复杂度是\ ...

  7. Spring Boot中使用@Async实现异步调用,加速任务的执行!

    什么是"异步调用"?"异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行 ...

  8. python库--pandas--文本文件读取

    .read_table() / read_csv()     filepath_or_buffer 文件路径 sep='\t' 分隔符. 设置为N, 将尝试自动确定 delimiter=N sep的备 ...

  9. docker部署rabbitmq集群

    docker版本:18.09.6 或以上 rabbitmq镜像版本:rabbitmq:3.9.5-management 一.拉镜像: docker pull rabbitmq:3.9.5-manage ...

  10. C# Collection

    数组与集合不同的适用范围: 数组:数组最适用于创建和使用固定数量的强类型化对象. 集合:集合提供更灵活的方式来使用对象组. 与数组不同,你使用的对象组随着应用程序更改的需要动态地放大和缩小. 对于某些 ...