Spring AOP全流程源码解析

1.入口

1.1 通过注解的方式开启aop功能

在一个配置类上使用@EnableAspectJAutoProxy注解,开启AOP功能。

java 复制代码
@EnableAspectJAutoProxy  
@Configuration  
public class AppConfig {}

我们看下@EnableAspectJAutoProxy的代码:

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	boolean proxyTargetClass() default false;

	boolean exposeProxy() default false;

}

我们看到在这个注解中,它引入了@Import(AspectJAutoProxyRegistrar.class)类,通过类名可以判断,这个类是用来注册AspectJ代理。然后我们再看下该类的代码:

java 复制代码
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 我们主要关心这行代码
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		// 剩余的代码都是一些属性赋值,暂时不关心
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}
}

再进入AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)方法:

java 复制代码
@Nullable  
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {    // 又调用了另外一个方法,顺着再看
   return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);  
}
  
@Nullable  
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(  
      BeanDefinitionRegistry registry, @Nullable Object source) {  
   // 就是这里了,注册了一个类到spring容器中
   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);  
}

我们看到最终其实调用了registerOrEscalateApcAsRequired()方法,并将AnnotationAwareAspectJAutoProxyCreator.class作为一个入参传入,看下该方法:

可以看到,最终就是将AnnotationAwareAspectJAutoProxyCreator.class注册到spring容器中,该类就是AOP的入口类了,细节稍后细谈。

1.2通过配置xml的方式开启aop功能

在配置文件中添加如下配置,开启AOP功能:

xml 复制代码
<!-- 启用aop -->
<aop:aspectj-autoproxy />

该标签,不是spring的默认标签,属于自定义标签。在配置文件的头声明中肯定有引入aop xml的校验文件: 然后在spring-aop的jar包中,有一个spring.handlers文件,通过上面的头声明,可以找到<aop:aspectj-autoproxy /> 标签的解析类:

xml 复制代码
http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

找到该类后,进入该类AopNamespaceHandler

java 复制代码
public class AopNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        // 主要看这行代码,就是我们xml中声明的标签
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }
}

我们主要看aspectj-autoproxy标签的注册逻辑,它注册了AspectJAutoProxyBeanDefinitionParser解析类。进入该类,主要看parse()方法: 是不是和"注解"方式开启AOP有点像了。再进入该方法: 这里它调用了AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法。和前面"注解"的逻辑就都一样了,就是将AnnotationAwareAspectJAutoProxyCreator注册到spring容器中。

1.3 初识入口类

从前两点,知道了AnnotationAwareAspectJAutoProxyCreator就是aop的入口类,先看一下他的继承结构:

可以看到该类实现了SmartInstantiationAwareBeanPostProcessor,它是一个BeanPostProcessor,也就是说在bean的初始化过程中,它是可以编辑、修改bean的。AOP初始化也就是从这里开始的:BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName)

2.AOP源码之旅

先导:几个重要、关键类

  • 个人经验,这一小节不要一开始就试图死记硬背,记住类结构。开始有个印象即可,后面看源码,理解源码逻辑的同时,再结合起来看(双屏真香~_~),边理解、边记忆,这样当你看懂源码的时候,这些类结构也记得7788了。
  • 在spring中,Advisor是持有增强(advice)和切点(pointCut)的对象:
  • Advisor的继承结构:
  • 几种增强类型的类结构:
  • 连接点(个人理解,组合调用advice,然后调用目标方法,起"连接"作用。即连接"增强"和"目标方法")结构:

2.1 AOP-获取"增强"

从前一章节,已经知晓入口类就是AnnotationAwareAspectJAutoProxyCreator,它实现了BeanPostProcessor接口。在spring初始化bean的流程中,就会调用其postProcessAfterInitialization()方法,该方法就是aop的入口了。于是乎,我们就从AnnotationAwareAspectJAutoProxyCreator类的该方法开始,它在其父类AbstractAutoProxyCreator中实现了该方法:

java 复制代码
@Override  
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {  
   if (bean != null) {  
      // 根据给定bean的class和name构建一个key。格式:beanName,若是beanFactory加一个前缀&  
      Object cacheKey = getCacheKey(bean.getClass(), beanName);  
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {  
         // 将需要增强的类,装饰成代理类  
         return wrapIfNecessary(bean, beanName, cacheKey); 
      }  
   }
   return bean;  
}

进入wrapIfNecessary()方法:

java 复制代码
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {  
   // 已经处理过,则直接返回  
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { 
      return bean;  
   }
   // 特殊类、指定的bean、已经创建代理的bean 无需"增强"
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;  
   }
   // 基础设施类(就是关于几个Advices、Pointcut的类) 或者 指定bean  不处理
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)){  
      this.advisedBeans.put(cacheKey, Boolean.FALSE);  
      return bean;  
   }  
  
   // Create proxy if we have advice.  
   // 获取适合当前bean的增强:返回的是List<Advisor>  
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);  
   if (specificInterceptors != DO_NOT_PROXY) {  
      this.advisedBeans.put(cacheKey, Boolean.TRUE);  
      // 创建具体的代理对象
      Object proxy = createProxy(  
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));  
      this.proxyTypes.put(cacheKey, proxy.getClass());  
      return proxy;  
   }  
  
   this.advisedBeans.put(cacheKey, Boolean.FALSE);  
   return bean;  
}

该方法主要流程就是调用getAdvicesAndAdvisorsForBean()方法,获取增强。然后再通过createProxy()方法创建代理对象。我们先看获取增强的逻辑:

java 复制代码
@Override  
@Nullable  
protected Object[] getAdvicesAndAdvisorsForBean(  
      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {  
   List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);  
   if (advisors.isEmpty()) {  
      return DO_NOT_PROXY;  
   }  
   return advisors.toArray();  
}

该方法是在父类AbstractAdvisorAutoProxyCreator中实现,就只调用了findEligibleAdvisors()方法,进入该方法,一探究竟:

java 复制代码
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {  
	// 在spring容器中寻找所有的advisor
   List<Advisor> candidateAdvisors = findCandidateAdvisors();  
   // 筛选适合当前bean的advisor
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); 
   extendAdvisors(eligibleAdvisors); // 扩展接口
   if (!eligibleAdvisors.isEmpty()) {  
      eligibleAdvisors = sortAdvisors(eligibleAdvisors); // 排序(根据Order注解来的)
   }  
   return eligibleAdvisors;  
}

findEligibleAdvisors()方法中,它先是查找spring容器中所有"增强",然后再筛选符合当前bean的"增强"。我们先看findCandidateAdvisors()查找所有增强的方法,因为我们注入容器的实例对象是AnnotationAwareAspectJAutoProxyCreator,所以调用的是该类的此方法:

java 复制代码
@Override  
protected List<Advisor> findCandidateAdvisors() {  
   // Add all the Spring advisors found according to superclass rules.  
   // 根据父类规则,获取其所有advisor(父类加载的是配置文件中声明的AOP,即实现了 Advisor 的类) 
   List<Advisor> advisors = super.findCandidateAdvisors();  
   // Build Advisors for all AspectJ aspects in the bean factory. 
   // 寻找基于注解@Aspect的切面  
   if (this.aspectJAdvisorsBuilder != null) {  
      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());  
   }  
   return advisors;  
}

可以看到该方法先调用了父类AbstractAdvisorAutoProxyCreator同名方法获取增强,先看一下父类获取增强的逻辑:

java 复制代码
protected List<Advisor> findCandidateAdvisors() {  
   Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");  
   return this.advisorRetrievalHelper.findAdvisorBeans();  
}

父类是利用一个辅助类BeanFactoryAdvisorRetrievalHelper来获取增强,进入该方法:

java 复制代码
public List<Advisor> findAdvisorBeans() {  
   // 判断缓存中是否已经有advisor 
   String[] advisorNames = this.cachedAdvisorBeanNames;  
   if (advisorNames == null) {  
// 获取容器中所有Advisor的beanName。此时容器中的advisor都是通过xml声明的。
// 通过注解声明的还没加载进来,也不会实现Advisor接口
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(  
            this.beanFactory, Advisor.class, true, false);  
      this.cachedAdvisorBeanNames = advisorNames;  
   }  
   if (advisorNames.length == 0) {
      return new ArrayList<>();  
   }  
  
   List<Advisor> advisors = new ArrayList<>();  
   for (String name : advisorNames) {
      if (isEligibleBean(name)) { // 默认返回true,可以覆盖方法  
         if (this.beanFactory.isCurrentlyInCreation(name)) { // 过滤正在创建中的bean
            if (logger.isTraceEnabled()) {  
               logger.trace("Skipping currently created advisor '" + name + "'");  
            }  
         }  
         else {  
            try {
	            // 直接从容器中获取Advisor
               advisors.add(this.beanFactory.getBean(name, Advisor.class));  
            }  
            catch (BeanCreationException ex) {  
               Throwable rootCause = ex.getMostSpecificCause();  
               if (rootCause instanceof BeanCurrentlyInCreationException) {  
                  BeanCreationException bce = (BeanCreationException) rootCause; 
                  String bceBeanName = bce.getBeanName();  
                  if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                     if (logger.isTraceEnabled()) { 
                        logger.trace("Skipping advisor '" + name +  
                              "' with dependency on currently created bean: " + ex.getMessage());
                     }  
                  }  
               }  
               throw ex;  
            }  
         }  
      }  
   }  
   return advisors;  
}

这里获取增强的逻辑比较简单,对照着写的注释理解,一目了然。从父类获取完增强后,然后我们返回AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()方法继续看子类获取增强的逻辑this.aspectJAdvisorsBuilder.buildAspectJAdvisors()进入该方法:

java 复制代码
/**
 * 返回所有添加了Aspect注解的bean,并返回advice方法
 */
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<>();
				/* 获取容器中所有的beanName */
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				// 循环beanName
				for (String beanName : beanNames) {
					// 不合法的bean则略过,由子类定义规则,默认返回true
					if (!isEligibleBean(beanName)) {
						continue;
					}
					Class<?> beanType = this.beanFactory.getType(beanName, false);
					if (beanType == null) {
						continue;
					}
					// 是否存在Aspect注解
					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);
							// 解析标记AspectJ注解类中的 增强方法
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); 
							if (this.beanFactory.isSingleton(beanName)) {
								// 若bean是单例,则直接缓存增强
								this.advisorsCache.put(beanName, classAdvisors); 
							}
							else {
								// 若bean不是单例,每次都要新获取,则缓存工厂类
								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);
							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;
}

这个方法的代码看着有点多,它是用于解析基于@Aspect注解的切面,主要流程如下:

  1. 判断缓存,是否已经加载过基于@Aspect注解的切面。若存在缓存,则直接从缓存中取增强。
  2. 缓存不存在,则获取spring IOC容器中所有的beanName。
  3. 循环所有beanName,判断对应的类是否存在@Aspect注解。
  4. 存在@Aspect注解,则解析其声明的增强、切点,然后缓存。 其主要流程,并不复杂。在这个方法中,我们重点学习解析增强的逻辑:
java 复制代码
MetadataAwareAspectInstanceFactory factory =  
      new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);  
// 解析标记了AspectJ注解的类,获取增强
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

可以看到,它首先用beanFactorybeanName构建了一个MetadataAwareAspectInstanceFactory对象,然后将其作为参数,调用了AspectJAdvisorFactory.getAdvisors()方法,真正实现该方法的是其子类ReflectiveAspectJAdvisorFactory。我们直接看ReflectiveAspectJAdvisorFactory.getAdvisors():

java 复制代码
@Override  
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {  
   /* 获取标记为 AspectJ 的class */  
   Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();  
   /* 获取标记为 AspectJ 的class name */  
   String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();  
   /* 对标记为 AspectJ 的类进行基本的验证 */   
   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<>();  
   // 获取本类及其父类的所有方法(排除了@point方法、抽象方法),并循环
   for (Method method : getAdvisorMethods(aspectClass)) {
      // 构建增强
      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.  
   // DeclareParents 注解作用:用来"给被代理对象添加一些方法"  
   for (Field field : aspectClass.getDeclaredFields()) {  
      Advisor advisor = getDeclareParentsAdvisor(field);  
      if (advisor != null) {  
         advisors.add(advisor);  
      }  
   }  
  
   return advisors;  
}

这里我们先看获取类所有方法的逻辑getAdvisorMethods(aspectClass)

java 复制代码
private List<Method> getAdvisorMethods(Class<?> aspectClass) {  
   List<Method> methods = new ArrayList<>();  
   // 获取类(父类)的所有方法,排除了@Pointcut注解的方法  
   ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter); 
   if (methods.size() > 1) {  
      methods.sort(adviceMethodComparator); // 排序  
   }  
   return methods;  
}

该方法,主要就是获取类的所有方法,然后对方法进行排序。我们关注一下排序的逻辑,调用的是List自带的sort()方法,传入一个Comparator对象,关键是这个Comparator对象:

java 复制代码
private static final Comparator<Method> adviceMethodComparator;  
  
static {  
   // 按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的顺序排序  
   Comparator<Method> adviceKindComparator = new ConvertingComparator<>(  
         new InstanceComparator<>(Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
         (Converter<Method, Annotation>) method -> {  
            AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);  
            return (ann != null ? ann.getAnnotation() : null);  
         });  
   Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);  
   adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);  
}

在这里,将方法按"增强"的类型,排了一下序,这里就是对"增强"进行了第一次排序。 然后我们返回getAdvisors()方法,接着看构建增强的方法getAdvisor()

java 复制代码
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()方法主要是解析注解上的信息(增强类型、切点表达式等),封装成AspectJExpressionPointcut对象,没有特殊的逻辑。这里我们主要看下返回实例InstantiationModelAwarePointcutAdvisorImpl对象(它是advisor的子类)的构造过程:

java 复制代码
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,  Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {  
  
   this.declaredPointcut = declaredPointcut;  
   this.declaringClass = aspectJAdviceMethod.getDeclaringClass();  
   this.methodName = aspectJAdviceMethod.getName();  
   this.parameterTypes = aspectJAdviceMethod.getParameterTypes();  
   this.aspectJAdviceMethod = aspectJAdviceMethod;  
   this.aspectJAdvisorFactory = aspectJAdvisorFactory;  
   this.aspectInstanceFactory = aspectInstanceFactory;  
   this.declarationOrder = declarationOrder;  
   this.aspectName = aspectName;  
   // 是否延迟加载  
   if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { 
      // Static part of the pointcut is a lazy type.  
      Pointcut preInstantiationPointcut = Pointcuts.union(  
            aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);  
  
      // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.  
      // If it's not a dynamic pointcut, it may be optimized out      // by the Spring AOP infrastructure after the first evaluation.      
      this.pointcut = new PerTargetInstantiationModelPointcut(  
            this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);  
      this.lazy = true;  
   }  
   else {  
      // A singleton aspect.  
      this.pointcut = this.declaredPointcut;  
      this.lazy = false;  
      // 实例化advice对象,会根据不通的环绕方式,封装成不同的advice  
      this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);  
   }  
}

构造函数中主要是给成员属性赋值,主要看下instantiatedAdvice对象的赋值:

java 复制代码
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {  
   Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,this.aspectInstanceFactory, this.declarationOrder, this.aspectName);  
   return (advice != null ? advice : EMPTY_ADVICE);  
}

继续进入this.aspectJAdvisorFactory.getAdvice()方法:

java 复制代码
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);  
   }  
  
   AbstractAspectJAdvice springAdvice;  
   // 根据不同的注解类型封装不同的advice
   switch (aspectJAnnotation.getAnnotationType()) {
      case 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);  
   }  
  
   // Now to configure the advice...  
   springAdvice.setAspectName(aspectName);  
   springAdvice.setDeclarationOrder(declarationOrder);  
   String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);  
   if (argNames != null) {  
      springAdvice.setArgumentNamesFromStringArray(argNames);  
   }  
   springAdvice.calculateArgumentBindings();  
   return springAdvice;  
}

在该方法中可以看到根据增强的类型不通,将增强分别注册成了:AspectJAroundAdvice、AspectJAfterAdvice、 AspectJMethodBeforeAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice.另外这里我们需要关注下springAdvice.calculateArgumentBindings()方法:

java 复制代码
public final void calculateArgumentBindings() {  
   // The simple case... nothing to bind.  
   // 没有入参,直接返回
   if (this.argumentsIntrospected || this.parameterTypes.length == 0) {   
      return;  
   }  
  
   int numUnboundArgs = this.parameterTypes.length;  
   Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();  
   if (maybeBindJoinPoint(parameterTypes[0]) // 绑定了参数 JoinPoint         
       || maybeBindProceedingJoinPoint(parameterTypes[0]) // 绑定了参数:ProceedingJoinPoint  
       || maybeBindJoinPointStaticPart(parameterTypes[0])) { // 绑定了参数:JoinPoint.StaticPart  
      // 注意该参数只能放在第一个位置,否则会报错。注意他们是aspectj包中的对象,不是spring的  
      numUnboundArgs--;  
   }  
  
   if (numUnboundArgs > 0) { // 绑定其他我们自定义的参数  
      // need to bind arguments by name as returned from the pointcut match  
      bindArgumentsByName(numUnboundArgs);  
   }  
  
   this.argumentsIntrospected = true;  
}

在这个方法中,我们就可以通过源码的方式知道,增强方法传参数时,如果入参有JoinPoint参数,那么它必须放在第一个入参。到这里,我们就已经知道spring是如何构建一个advisor对象的了。代码逻辑中,还有"延迟加载的增强"、"引介增强"的逻辑,由于平时也没用到过,就暂时都没研究了。我们再返回到getAdvisors()方法,可以看到它获取到advisor的List对象也就直接返回了。接着我们返回上一层继续看findEligibleAdvisors()方法,再回顾一下:

java 复制代码
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {  
   // 在spring容器中寻找所有的advisor
   List<Advisor> candidateAdvisors = findCandidateAdvisors(); 
   // 寻找适合当前bean的advisor
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); 
   extendAdvisors(eligibleAdvisors); // 扩展接口  
   if (!eligibleAdvisors.isEmpty()) {
	  // 排序(根据Order注解来排)
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);   
   }  
   return eligibleAdvisors;  
}

在得到容器中所有的advisor后,接着看findAdvisorsThatCanApply()方法,筛选适合当前bean的Advisor

java 复制代码
protected List<Advisor> findAdvisorsThatCanApply(  
      List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {  
   // 使用了ThreadLocal保证线程安全
   ProxyCreationContext.setCurrentProxiedBeanName(beanName);   
   try { 
	  // 寻找适合当前bean的增强
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);   
   }  
   finally {  
      ProxyCreationContext.setCurrentProxiedBeanName(null);  
   }  
}

可以看到spring将筛选的步骤,交给了AopUtils类来做,进入该方法:

java 复制代码
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {  
   if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;  
   }  
   List<Advisor> eligibleAdvisors = new ArrayList<>();  
   for (Advisor candidate : candidateAdvisors) {  
      // 判断 引介增强(DeclareParents注解声明的增强) 是否符合增强当前bean  
      if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {  
         eligibleAdvisors.add(candidate);  
      }
   }  
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();  
   for (Advisor candidate : candidateAdvisors) {
      // "引介增强" 前面已经判断过了,直接跳过
      if (candidate instanceof IntroductionAdvisor) {
         // already processed
         continue;
      }
      // 判断增强是否符合当前bean
      if (canApply(candidate, clazz, hasIntroductions)) {
         eligibleAdvisors.add(candidate);
      }  
   }  
   return eligibleAdvisors;  
}

判断增强是否符合当前bean主要是通过canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions)方法:

java 复制代码
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {  
   if (advisor instanceof IntroductionAdvisor) { // 引介增强  
      return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);  
   }
   //在前面是初始化成 InstantiationModelAwarePointcutAdvisorImpl对象,它是PointcutAdvisor的子类 
   else if (advisor instanceof PointcutAdvisor) {  
      PointcutAdvisor pca = (PointcutAdvisor) advisor;  
      return canApply(pca.getPointcut(), targetClass, hasIntroductions);  
   }  
   else {  
      // It doesn't have a pointcut so we assume it applies.  
      // 如果增强没有设置切点信息,我们假设这个增强是适合当前bean的
      return true;  
   }  
}

再进入canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)(重载)方法:

java 复制代码
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {  
   Assert.notNull(pc, "Pointcut must not be null");  
   // 最终判断,是由aspectJ jar进行逻辑判断的
   if (!pc.getClassFilter().matches(targetClass)) {   
      return false;  
   }  
  
   MethodMatcher methodMatcher = pc.getMethodMatcher();  
   if (methodMatcher == MethodMatcher.TRUE) {  
      // No need to iterate the methods if we're matching any method anyway...  
      return true;  
   }  
  
   IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;  
   if (methodMatcher instanceof IntroductionAwareMethodMatcher) {  
      introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;  
   }  
  
   Set<Class<?>> classes = new LinkedHashSet<>();  
   if (!Proxy.isProxyClass(targetClass)) {  
      classes.add(ClassUtils.getUserClass(targetClass));  
   }  
   classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));  
  
   for (Class<?> clazz : classes) {  
      Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);  
      for (Method method : methods) {  
         if (introductionAwareMethodMatcher != null ?  
               introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
               methodMatcher.matches(method, targetClass)) {// 方法级别上判断,是否符和当前bean
            return true;  
         }  
      }  
   }  
   return false;  
}

可以看到判断"增强"是否适合当前bean,主要是利用PointCut接口获取ClassFilterMethodMatcher实例,然后调用其matches()方法进行判断。但最终的实现用的是aspectJ三方jar包的功能。这里主要学习spring的源码逻辑,具体逻辑,就不细究了,感兴趣的可以搜索相关资料看看(目前个人没啥兴趣~_~)。至此已经筛选出符合当前bean的增强了。然后再次返回findEligibleAdvisors()方法,再次对增强,排了一次序,但这次是根据@Order来排的。ok,至此成功获取符合当前bean的增强了。

2.2 创建代理对象

  • 本文主要学习基于java接口动态代理的AOP。在看spring如何创建代理对象前,先回顾一下java的动态代理:动态代理
  • 前面我们已经获取到了适合当前bean的增强对象。接下来就是创建代理对象了,接着返回看AbstractAutoProxyCreator.wrapIfNecessary()方法,看其中创建代理对象的方法:
java 复制代码
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,  
      @Nullable Object[] specificInterceptors, TargetSource targetSource) {  
  
   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {  
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);  
   }  
  
   ProxyFactory proxyFactory = new ProxyFactory();  
   proxyFactory.copyFrom(this); // 复制当前类的属性  
  
   if (proxyFactory.isProxyTargetClass()) {   
      // 基于JDK动态代理  
      if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {  
         // 获取类的接口,并将接口赋值到代理工厂类中
         for (Class<?> ifc : beanClass.getInterfaces()) { 
            proxyFactory.addInterface(ifc);  
         }  
      }  
   }  
   else {  
      // No proxyTargetClass flag enforced, let's apply our default checks...  
      if (shouldProxyTargetClass(beanClass, beanName)) {  
         proxyFactory.setProxyTargetClass(true);  
      }  
      else {  
         evaluateProxyInterfaces(beanClass, proxyFactory);  
      }  
   }  
  
   /*将所有增强都装饰成advisor(除了自己写的增强,还有部分公共增强,默认是没有公共的增强的)*/  
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);  
   proxyFactory.addAdvisors(advisors); // 加入增强  
   proxyFactory.setTargetSource(targetSource); // 设置要代理的类  
   customizeProxyFactory(proxyFactory); // 定制化代理类(可扩展接口)  
  
   /*用来控制代理工厂被配置之后,是否还允许修改通知。默认值为false(即在代理被配置后,不允许修改代理的配置)*/  
   proxyFactory.setFrozen(this.freezeProxy);  
   if (advisorsPreFiltered()) {  
      proxyFactory.setPreFiltered(true);  
   }  
  
   ClassLoader classLoader = getProxyClassLoader();  
   if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {  
      classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();  
   }  
   // 通过工厂类创建代理对象
   return proxyFactory.getProxy(classLoader);
}

可以看到代理类是通过工厂类创建的,我们先看下proxyFactory的继承结构:

源码中对Advised类的释义是:AOP代理工厂的父类,该工厂必须含有一个配置清单,清单含有Interceptors和其他advice, Advisors,和代理接口。我们接着看工厂类创建代理的过程proxyFactory.getProxy()方法:

java 复制代码
public Object getProxy(@Nullable ClassLoader classLoader) {  
   return createAopProxy().getProxy(classLoader);  
}

接着看createAopProxy()方法:

java 复制代码
protected final synchronized AopProxy createAopProxy() {  
   if (!this.active) {  
      activate();  
   }  
   return getAopProxyFactory().createAopProxy(this);  
}

先是调用getAopProxyFactory()方法获取AOP代理工厂类,其实就是DefaultAopProxyFactory类,接着看该类的createAopProxy()方法:

java 复制代码
@Override  
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {  
   if (!NativeDetector.inNativeImage() && 
	     // 用来控制通过CGLIB创建的代理使用激进的优化策略。除非完全了解AOP代理处理优化,否则不推荐用户使用这个设置。目前这个属性只用于CGLIB代理   
         (config.isOptimize() 
	            // 这个属性为true时,目标类本身被代理而不是目标类的接口。true,创建CGLIB代理。设置方式:<aop:aspectj-autoproxy- proxy-target-class="true"/>  
               || config.isProxyTargetClass() 
                // 是否存在代理类(没有实现接口,创建CGLIB代理;)  
               || hasNoUserSuppliedProxyInterfaces(config))) { 
      Class<?> targetClass = config.getTargetClass();  
      if (targetClass == null) {  
         throw new AopConfigException("TargetSource cannot determine target class: " +  
               "Either an interface or a target is required for proxy creation.");  
      }  
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
         // 符合一定条件,创建JDK动态代理 
         return new JdkDynamicAopProxy(config);  
      }  
      return new ObjenesisCglibAopProxy(config);  
   }  
   else {  
      return new JdkDynamicAopProxy(config);  
   }  
}

可以看到返回了一个JdkDynamicAopProxy实例,然后看下该类的继承结构:

java 复制代码
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable{}

看到没!它实现了InvocationHandler接口,是不是熟悉的感觉了。那么该类必定会有一个invoke()方法和getProxy()方法。我们先看下它的getProxy()方法:

java 复制代码
public Object getProxy(@Nullable ClassLoader classLoader) {  
   if (logger.isTraceEnabled()) {  
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());  
   }
   // 返回代理对象  
   return Proxy.newProxyInstance(determineClassLoader(classLoader),this.proxiedInterfaces, this);
}

看到这行返回代理对象的代码,是不是和我们自己编写、基于接口的java动态代理的逻辑一毛一样了了。然后我们再看下它的构造函数,了解一下他的结构:

java 复制代码
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {  
   Assert.notNull(config, "AdvisedSupport must not be null");  
   if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {  
      throw new AopConfigException("No advisors and no TargetSource specified");  
   }
   this.advised = config;  
   // 代理的接口
   this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); 
   findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces); // 是否有equal和hashCode方法  
}

这里主要赋值了advised属性和proxiedInterfaces,这里我们再回顾一下Advised对象释义:它AOP代理工厂的父类,该工厂必须含有一个配置清单,清单含有Interceptors 和其他 advice, Advisors,和代理接口。这样就创建好一个代理对象了。

2.3 调用一个方法的增强流程

通过上一节,我们已经获取到了代理对象JdkDynamicAopProxy,那么当我们调用一个方法时,必定是先执行JdkDynamicAopProxy.invoke()方法:

java 复制代码
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;

	TargetSource targetSource = this.advised.targetSource;
	Object target = null;

	// ...
	// 省略了一些无关主流程的代码
	// ...
	Object retVal;

	target = targetSource.getTarget();
	Class<?> targetClass = (target != null ? target.getClass() : null);

	// Get the interception chain for this method.
	// 获取适合当前方法的拦截器链(即增强),会把advisor封装成MethodInterceptor对象
	List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

	if (chain.isEmpty()) {
		// 如果没有发现任何拦截器,则直接调用切点方法
		Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
		retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
	}
	else {
		// 将拦截器封装在ReflectiveMethodInvocation
		// 以便使用其proceed方法,进行递归调用
		MethodInvocation invocation =
				new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
		// Proceed to the joinpoint through the interceptor chain.
		retVal = invocation.proceed();
	}

	Class<?> returnType = method.getReturnType();
	if (retVal != null && retVal == target &&
			returnType != Object.class && returnType.isInstance(proxy) &&
			!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
		retVal = proxy;
	}
	else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
		throw new AopInvocationException(
				"Null return value from advice does not match primitive return type for: " + method);
	}
	return retVal;
}

整体流程:

  • 获取适合当前方法的拦截器链(即增强)
  • 调用拦截器链,返回执行结果

先看this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)获取拦截器链的逻辑:

java 复制代码
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
   MethodCacheKey cacheKey = new MethodCacheKey(method);  
   List<Object> cached = this.methodCache.get(cacheKey);  
   if (cached == null) {  
      cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(  
            this, method, targetClass);  
      this.methodCache.put(cacheKey, cached);  
   }  
   return cached;  
}

又将"获取拦截器链"的功能委托给了advisorChainFactory对象,进入该类:

java 复制代码
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
	Advisor[] advisors = config.getAdvisors(); // 增强对象
	List<Object> interceptorList = new ArrayList<>(advisors.length);
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	Boolean hasIntroductions = null;

	for (Advisor advisor : advisors) { // 循环增强
		// 由切点驱动的增强(我们大部分的切面增强,应该都是这个)
		if (advisor instanceof PointcutAdvisor) {
			// Add it conditionally.
			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
			// 再次校验了增强是否符和当前bean
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				boolean match;
				if (mm instanceof IntroductionAwareMethodMatcher) {
					if (hasIntroductions == null) {
						hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
					}
					match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
				}
				else {
					match = mm.matches(method, actualClass);
				}
				// 如果增强适合当前方法,将增强装饰成拦截器(MethodInterceptor)
				if (match) {
					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
					if (mm.isRuntime()) {
						for (MethodInterceptor interceptor : interceptors) {
							interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
						}
					}
					else {
						interceptorList.addAll(Arrays.asList(interceptors));
					}
				}
			}
		}
		// 引介增强
		else if (advisor instanceof IntroductionAdvisor) {
			IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
			if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		else {
			Interceptor[] interceptors = registry.getInterceptors(advisor);
			interceptorList.addAll(Arrays.asList(interceptors));
		}
	}
	return interceptorList;
}

获取拦截链的流程,我们主要看下将advisor适配成MethodInterceptor的逻辑:registry.getInterceptors(advisor)。spring是将它委托了给DefaultAdvisorAdapterRegistry类,进入该类:

java 复制代码
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {  
   List<MethodInterceptor> interceptors = new ArrayList<>(3);  
   Advice advice = advisor.getAdvice();  
   // 实现了MethodInterceptor接口的,直接添加(AspectJAroundAdvice、AspectJAfterAdvice、AspectJAfterThrowingAdvice) 
   if (advice instanceof MethodInterceptor) {  
      interceptors.add((MethodInterceptor) advice);  
   }  
   // 没有实现MethodInterceptor接口的,利用适配器适配(AspectJMethodBeforeAdvice、AspectJAfterReturningAdvice)  
   for (AdvisorAdapter adapter : this.adapters) {  
      if (adapter.supportsAdvice(advice)) {  
         interceptors.add(adapter.getInterceptor(advisor));  
      }  
   }  
   if (interceptors.isEmpty()) {  
      throw new UnknownAdviceTypeException(advisor.getAdvice());  
   }  
   return interceptors.toArray(new MethodInterceptor[0]);  
}

没有实现MethodInterceptor接口的增强类型,被适配之后的类:

原始增强类 适配后的类
AspectJMethodBeforeAdvice MethodBeforeAdviceInterceptor
AspectJAfterReturningAdvice AfterReturningAdviceInterceptor

Advisor装饰成MethodInterceptor(拦截器)后,接着就是执行拦截器(增强)了。它先是初始化了一个ReflectiveMethodInvocation对象:

java 复制代码
protected ReflectiveMethodInvocation(  
      Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {  
this.proxy = proxy; // 代理对象  
this.target = target; // 真正的bean对象
this.targetClass = targetClass; // 目标类的class对象  
this.method = BridgeMethodResolver.findBridgedMethod(method); // 要执行的目标方法  
// 目标方法的参数  
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
// 拦截器链 
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; 
}

接着我们看下ReflectiveMethodInvocation类的继承结构:

可以看到ReflectiveMethodInvocation其实是一个Joinpoint。看到这里,可以在再仔细回忆、思考一下spring中连接点Joinpint的含义。我也是学习到这里才对连接点的含义逐渐清晰,之前看别人的解释,总是一知半解。另外AspectJ jar包中也有一个JoinPoint类,看代码的时候注意区别一下,别搞混淆了(我就混淆了,好一会才反应过来)。

接着看真正执行拦截器(增强)的方法ReflectiveMethodInvocation.proceed()

java 复制代码
public Object proceed() throws Throwable {
	// We start with an index of -1 and increment early.
	// 执行完所有增强后,执行"目标"方法
	if (this.currentInterceptorIndex==this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}
	// 取出下一个"增强"
	Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		InterceptorAndDynamicMethodMatcher dm =
				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		// 动态匹配调用
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { 
			return dm.interceptor.invoke(this);
		} else {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			// 不匹配则不执行当前拦截器,执行下一个
			return proceed();
		}
	}
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		// 普通拦截器,直接调用拦截器。
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

我们的增强一般都是普通"拦截器",都是直接调用MethodInterceptor.invoke,我们的增强对象在前面说过,要不实现了MethodInterceptor接口,要不已经被适配成了MethodInterceptor子类。我们按照增强类型,一个一个看过来:

  • @Around 对应AspectJAroundAdvice类: 直接看该类的invoke()方法:
java 复制代码
public Object invoke(MethodInvocation mi) throws Throwable {
	if (!(mi instanceof ProxyMethodInvocation)) {
		throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
	}
	ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
	// 注意注意,就是在这一步,把spring的Joinpoint对象转化为了Aspectj的JoinPoint对象
	ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
	JoinPointMatch jpm = getJoinPointMatch(pmi);
	return invokeAdviceMethod(pjp, jpm, null, null); // 调用增强方法
}

我们再接着看调用增强的方法invokeAdviceMethod(),它是在父类AbstractAspectJAdvice中实现的:

java 复制代码
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,  
      @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {  
   return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));  
}

它先是调用argBinding()方法获取目标方法的参数列表,然后将其作为入参,调用invokeAdviceMethodWithGivenArgs()方法:

java 复制代码
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
	Object[] actualArgs = args;
	if (this.aspectJAdviceMethod.getParameterCount() == 0) {
		actualArgs = null;
	}
	try {
		ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
		// 执行增强方法
		return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs); 
	}
	catch (IllegalArgumentException ex) {
		throw new AopInvocationException("Mismatch on arguments to advice method [" +
				this.aspectJAdviceMethod + "]; pointcut expression [" +
				this.pointcut.getPointcutExpression() + "]", ex);
	}
	catch (InvocationTargetException ex) {
		throw ex.getTargetException();
	}
}

没有特殊、复杂的逻辑。执行到这里,它就会调用环绕增强,比如我们前面的例子:

这里需要注意,环绕通知的增强方法,第一个入参必须是ProceedingJoinPoint,在执行完前置逻辑后,调用point.proceed()方法,继续调用下一个增强。要不然程序就在这里中断了。

  • @Before 对应AspectJMethodBeforeAdvice,但未实现MethodInterceptor接口,被装饰为MethodBeforeAdviceInterceptor类,直接看他的invoke()方法:
java 复制代码
public Object invoke(MethodInvocation mi) throws Throwable {  
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());  
   return mi.proceed();  
}

可以看到它直接先是调用的advice.before方法,即增强内容AspectJMethodBeforeAdvice.before()方法:

java 复制代码
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {  
   invokeAdviceMethod(getJoinPointMatch(), null, null);  
}

它和AspectJAroundAdvice一样,都是通过调用父类AbstractAspectJAdvice.invokeAdviceMethod()方法,来执行增强方法的。执行完增强方法后,再调用mi.proceed()方法,递归继续执行下一个增强。

  • @After 对应AspectJAfterAdvice类,直接看他的invoke()方法:
java 复制代码
public Object invoke(MethodInvocation mi) throws Throwable {  
   try {  
      return mi.proceed();  
   }  
   finally {  
      invokeAdviceMethod(getJoinPointMatch(), null, null);  
   }  
}

可以看到它是直接调用了mi.proceed()方法,先递归执行下一个增强,然后在finally中再执行增强方法。

  • @AfterReturning 对应AspectJAfterReturningAdvice类,但未实现MethodInterceptor接口,被装饰为AfterReturningAdviceInterceptor类,直接看他的invoke()方法:
java 复制代码
public Object invoke(MethodInvocation mi) throws Throwable {  
   Object retVal = mi.proceed();  
   this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); 
   return retVal;  
}

可以看到,它是先直接调用mi.proceed()方法,先递归执行下一个增强,然后再执行增强方法this.advice.afterReturning():

java 复制代码
public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {  
   if (shouldInvokeOnReturnValueOf(method, returnValue)) {  
      invokeAdviceMethod(getJoinPointMatch(), returnValue, null);  
   }  
}

可以看到后置通知,它可以将"目标方法"的返回值,传入后置增强方法中的。

  • @AfterThrowing 对应AspectJAfterThrowingAdvice类,直接看他的invoke()方法:
java 复制代码
public Object invoke(MethodInvocation mi) throws Throwable {  
   try {  
      return mi.proceed();  
   }  
   catch (Throwable ex) {  
      if (shouldInvokeOnThrowing(ex)) {  
         invokeAdviceMethod(getJoinPointMatch(), null, ex);  
      }  
      throw ex;  
   }  
}

可以看到,它是先直接调用mi.proceed()方法递归执行下一个增强。假如目标方法执行过程中,抛出异常了,就会调用其增强方法。

  • 看源码过程中,发现还有一个增强ThrowsAdviceInterceptor,看其效果和AspectJAfterThrowingAdvice一样。要求增强类实现ThrowsAdvice接口。至今个人没有用过。感兴趣的小伙伴可以研究一下。
  • 看完5种增强类型的源码,也可以看出他们的执行顺序必定是:Around或Before >> AfterReturning >> AfterThrowing >> After

3.总结

以上就是spring AOP基于java动态代理的源码。spring源码被称为"面对对象"语言的典范,带着"面对对象"的思想去读spring的源码也会另一番收获。我在读spring源码时,常常看着看着就不知道跳到那个类去了,所以针对各个类画时序图就非常重要了,各位也可以尝试。下面是我在阅读时,关于各个流程画的时序图,供参考:

个人理解,如有错误欢迎评论区指正。也希望有小伙伴可以一起交流讨论、欢迎评论区留言。

网页上由于查看类的继承结构,方法跳转等诸多限制,阅读源码,强烈建议在IDE中阅读。本人阅读spring源码的记录:gitee.com/longshunche...

参考图书:郝佳前辈的《spring源码深度解析》

相关推荐
myNameGL11 分钟前
linux安装idea
java·ide·intellij-idea
青春男大13 分钟前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
HaiFan.1 小时前
SpringBoot 事务
java·数据库·spring boot·sql·mysql
2401_882727571 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·前端框架
我要学编程(ಥ_ಥ)1 小时前
一文详解“二叉树中的深搜“在算法中的应用
java·数据结构·算法·leetcode·深度优先
music0ant1 小时前
Idea 添加tomcat 并发布到tomcat
java·tomcat·intellij-idea
计算机徐师兄1 小时前
Java基于SSM框架的无中介租房系统小程序【附源码、文档】
java·微信小程序·小程序·无中介租房系统小程序·java无中介租房系统小程序·无中介租房微信小程序
源码哥_博纳软云2 小时前
JAVA智慧养老养老护理帮忙代办陪诊陪护小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
追逐时光者2 小时前
.NET 在 Visual Studio 中的高效编程技巧集
后端·.net·visual studio
大梦百万秋2 小时前
Spring Boot实战:构建一个简单的RESTful API
spring boot·后端·restful