·

老生常谈系列之Aop--Spring Aop源码解析(一)

老生常谈系列之Aop--Spring Aop源码解析(一)

前言

上一篇文章老生常谈系列之Aop--Spring Aop原理浅析大概阐述了动态代理的相关知识,并且最后的图给了一个Spring Aop实现的逻辑猜测,这是一种很普通的情形,如下图:

那下面,我们就通过源码分析来看Spring到底是怎么操作的,Spring是如何识别切面并且生成动态代理的。

在讲解Spring Aop实现之前,插两句Spring IOC的实现,因为Aop是依赖了IOC的实现的。可以参考Spring官网的原文如下:

One of the key components of Spring is the AOP framework. 
While the Spring IoC container does not depend on AOP (meaning you do not need to use AOP if you don’t want to), 
AOP complements Spring IoC to provide a very capable middleware solution.

翻译一下:算了,懒得翻了,这应该都能看懂。唉,还是翻译一下吧。Aop是Spring框架的一个重要组件,Ioc容器是不依赖Aop的,如果你不需要使用Aop你可以不管它。Aop完善了Spring Ioc的功能,提供了一个强大的中间件解决方案。中间件解决方案这要说一下了,Sentinel就是用了Aop去实现的,有兴趣可以去看一下它的代码SentinelResourceAspect

再看一句抄自5.2. Spring AOP Capabilities and Goals的:

Spring AOP’s approach to AOP differs from that of most other AOP frameworks. 
The aim is not to provide the most complete AOP implementation (although Spring AOP is quite capable).
Rather, the aim is to provide a close integration between AOP implementation and Spring IoC, to help solve common problems in enterprise applications.

翻译一下:Spring Aop实现的思路跟其他的Aop框架是不一样的。它的目标不是提供完整的Aop功能(尽管Spring Aop已经相当完整了),相反,它意在提供Aop和Spring Ioc容器间的集成以更好地解决企业级应用中普遍存在的问题。

好了,那么Aop依赖了Ioc,这话从何谈起,哪里产生了依赖。相信大家如果看过Spring源码,都知道BeanPostProcessor这个处理器,它是用于在Bean初始化的前后提供定制化的操作的。摘抄注释看一下:

 Factory hook that allows for custom modification of new bean instances —
for example, checking for marker interfaces or wrapping beans with proxies.

翻译一下:BeanPostProcessor允许自定义修改bean实例,例如检查标记接口或者用代理包装bean。看了BeanPostProcessor注释后,那么反过来再看一下上图Spring收集好切面后,是不是就是要在Bean初始化的时候判断,这个Bean是不是被切了,是否需要进行代理?这很符合Spring的尿性,毫无疑问,Spring就是这样实现的。

源码分析

以下代码分析基于Spring版本5.2.x,另外部分地方我摘抄保留了英文注释,希望看官可以用心体会。

从上面的分析可知,入口在BeanPostProcessor这个接口,那么Aop功能里实现了BeanPostProcessor接口的类,就是连接Ioc和Aop的桥梁的,这里直接把幕后真凶揪出来,就是AbstractAutoProxyCreator,可以先记住这玩意,这是我们创建Aop代理的核心类。

接下來的分析是假设你已经对Spring Ioc有一定了解的基础上进行的,否则形如BeanPostProcessor看起来都非常懵逼的话可能效果会不太好。建议先看Spring Ioc 源码分析系列

那接下来,我们开始Aop部分的源码解析之旅,限于文章的篇幅,这篇只会讨论Spring获取切面增强的部分,生产动态代理的在下一篇老生常谈系列之Aop--Spring Aop源码解析(二)阐述。

AspectJAutoProxyRegistrar注册器注册AnnotationAwareAspectJAutoProxyCreator

先来看AspectJAutoProxyRegistrar,回忆上一篇文章的例子,我们是通过下列代码

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

来开启Aop支持的,这里的关键是@EnableAspectJAutoProxy注解,我们跟进查看@EnableAspectJAutoProxy的代码。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * 是否强制使用CGLIB代理
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * 是否暴露代理到上下文,这里用来处理同一个类间方法调用代理不生效的问题
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;

}

可以看到有两个属性,注释如上,但是这里重点在类上的注解@Import(AspectJAutoProxyRegistrar.class),这里引入了AspectJAutoProxyRegistrar类,这个类实现了ImportBeanDefinitionRegistrar,只有一个实现方法,在注册BeanDefinition的时候会调用其registerBeanDefinitions()方法注册想要的BeanDefinition。这里涉及Spring Ioc 部分的@Import注解实现原理,可以参考Spring容器中@Import注解的实现原理。下面把AspectJAutoProxyRegistrar的代码贴出来。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * Register, escalate, and configure the AspectJ auto proxy creator based on the value
	 * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
	 * {@code @Configuration} class.
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		//向容器注册一个基于注解的自动代理创建器
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			//表示强制指定了要使用CGLIB
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			//表示强制暴露bean的代理对象到AopContext
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

这个类的作用是注册一个AnnotationAwareAspectJAutoProxyCreator,并且根据proxyTargetClassexposeProxy属性进行了设置。通过xml方式<aop:aspectJ-autoproxy/> 开启Aop也是注册了这个类,所以到了注册AnnotationAwareAspectJAutoProxyCreator后,xml的实现和注解的实现殊途同归。

一路跟进AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);方法的实现

	@Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

		// 如果已经存在了自动代理创建器且存在的自动代理创建器与现在的不一致,则要根据优先级来判断到底需要使用哪个
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					// 改变bean最重要的就是改变bean所对应的className属性
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			// 如果已经存在了自动代理创建器且存在的自动代理创建器与现在的一致,那么无需再创建
			return null;
		}

		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

以上代码中实现了自动注册AnnotationAwareAspectJAutoProxyCreator类的功能,同时这里还涉及了一个优先级的问题,如果已经存在了自动代理创建器,而且存在的自动代理创建器与现在的不一致,那么需要根据优先级来判断到底需要使用哪个。

注册好了AnnotationAwareAspectJAutoProxyCreator后,Spring注册了AnnotationAwareAspectJAutoProxyCreator,那么肯定就是用到了它提供的功能,接下来就分析AnnotationAwareAspectJAutoProxyCreator的功能。先来看一下AnnotationAwareAspectJAutoProxyCreator的继承关系。

1641267265004

可以看到继承的层次还是比较多的,但是这里可以重点关注AbstractAutoProxyCreator类,这个父类完成了绝大数的逻辑,这也符合Spring的尿性,Spring一般是由抽象父类实现大部分通用的逻辑。Spring里面的例子比比皆是,例如AbstractApplicationContextAbstractBeanFactoryAbstractHandlerMethodMapping等等。

到这里,分析进入了一个关键点,注册了AnnotationAwareAspectJAutoProxyCreator,而AnnotationAwareAspectJAutoProxyCreator实现了AbstractAutoProxyCreator,那下面的重点逻辑就落入了AbstractAutoProxyCreator里面,接下来分析AbstractAutoProxyCreator的实现。

AbstractAutoProxyCreator实现Aop和Ioc整合

上面我们说了,Aop与Ioc的整合是通过BeanPostProcessor来实现的,我们精简一下AbstractAutoProxyCreator的继承结构如下。

1641282224843

AbstractAutoProxyCreator实现了三个接口,其中关键的是BeanPostProcessor,BeanPostProcessor里有两个方法postProcessBeforeInitialization(Object bean, String beanName)postProcessAfterInitialization(Object bean, String beanName)。这两个方法分别提供了再Bean初始之前和之后的回调操作,Aop的核心奥义在AbstractAutoProxyCreator#postProcessAfterInitialization(@Nullable Object bean, String beanName),Spring在这里判断是否需要代理,那么接下来我们就分析AbstractAutoProxyCreator的实现。

	/**
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			// /根据给定的 bean的class和name构建一个key,格式:beanClassName_beanName
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			/**
			 * 当bean被循环引用,并且被暴露了
			 * 则会通过getEarlyBeanReference来创建代理类
			 * 通过判断earlyProxyReferences中是否存在beanName来决定是否需要对target进行动态代理
			 */
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				//该方法将会返回代理类
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

我们来看一下到达wrapIfNecessary()的调用链,这部分是Ioc的逻辑,所以这里简单贴出个调用链,不深入分析。

AbstractApplicationContext#refresh() ->
AbstractApplicationContext#finishBeanFactoryInitialization() ->
DefaultListableBeanFactory#preInstantiateSingletons() ->
AbstractBeanFactory#getBean() ->
AbstractBeanFactory#doGetBean() ->
DefaultSingletonBeanRegistry#getSingleton() ->
AbstractAutowireCapableBeanFactory#createBean() ->
AbstractAutowireCapableBeanFactory#doCreateBean() ->
AbstractAutowireCapableBeanFactory#initializeBean() ->
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization() ->
AbstractAutoProxyCreator#postProcessAfterInitialization()

以上是Spring Ioc获取Bean的经典调用链,可以看到Aop的实现是整合进入了这个调用链里,所以关键点在于wrapIfNecessary(bean, beanName, cacheKey)方法里,先来看一下它的时序图。

1641366209124

通过时序图可以清晰看到调用的过程,那么接下来就分析一下这个过程。首先看getAdvicesAndAdvisorsForBean(),看方法名就是获取所有的AdvicesAdvisors,那我们就从这开始获取切面增强方法之路。

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

对于指定 bean 的增强方法的获取一定是包含两个步骤的, 获取所有的增强以及寻找所有增强中适用于 bean 的增强并应用, 那么findCandidateAdvisors findAdvisorsThatCanApply 便是做了这两件事情。 当然,如果无法找到对应的增强器便返回 DO_NOT_PROXY,其中DO_NOT_PROXY=null

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

由于我们分析的是使用注解进行的 AOP,所以对于 自findCandidateAdvisors的实现其实是由 AnnotationAwareAspectJAutoProxyCreator 类完成的,子类的实现覆盖了父类的实现,我们继续跟踪 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors ()方法。

	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
        // 当使用注解方式配置 AOP 的时候并不是丢弃了对 XML 配置的支持,
        // 在这里调用父类方法加载配置文件中的 AOP 声明
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
            // 这里获取当前BeanFactory中所有被@Aspect注释的bean,并且获取bean中定义的切面
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

AnnotationAwareAspectJAutoProxyCreator 间接继承了 AbstractAdvisorAutoProxyCreator, 在实现获取切面方法中除了保留父类的获取配置文件中定义的增强外,同时添加了获取 Bean 的注解增强的功能,那么其实现正是由 this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 来实现的。

这一步是相当繁杂的,这里获取当前BeanFactory中所有被@Aspect注释的bean,并且获取bean中定义的切面,想一下,如果你是来实现,会怎么做?这里思考一下,可能有以下几步:

  • 获取当前BeanFactory中的所有的Bean
  • 获取所有被@Aspect注解标注的Bean
  • 解析提取出其中的切面增强方法
  • 放入缓存advisorsCacheaspectFactoryCache

那么下面来分析一下Spring Aop是不是这样实现的。

BeanFactoryAspectJAdvisorsBuilder构建切面增强方法

先来看buildAspectJAdvisors()方法,方法略长,为了能够展示所有细节,这里不做代码缩减,将代码全部贴出,可以跟着注释看一下,这里实现的逻辑顺序,就是我们上面分析的几点,看来Spring也是平常人的思路,所以不要慌,问题不大。

	/**
	 * Look for AspectJ-annotated aspect beans in the current bean factory,
	 * and return to a list of Spring AOP Advisors representing them.
	 * <p>Creates a Spring Advisor for each AspectJ advice method.
	 * @return the list of {@link org.springframework.aop.Advisor} beans
	 * @see #isEligibleBean
	 */
	public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = this.aspectBeanNames;

		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
					// 获取所有beanName
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					// 循环所有beanName找到对应的增强方法
					for (String beanName : beanNames) {
						// 如果bean不合法则略过,由子类定义规则,默认返回true
						if (!isEligibleBean(beanName)) {
							continue;
						}
						// We must be careful not to instantiate beans eagerly as in this case they
						// would be cached by the Spring container but would not have been weaved.
						// 获取对应的bean类型
						Class<?> beanType = this.beanFactory.getType(beanName);
						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)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								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;
	}

这里比较重要也是最为繁杂的方法是List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory),这里会进行Advisor的提取,具体实现类为ReflectiveAspectJAdvisorFactory

ReflectiveAspectJAdvisorFactory获取Advisor

获取Advisor

接下来的逻辑在ReflectiveAspectJAdvisorFactory类里,首先跟着注释看一下getAdvisors()方法。

	@Override
	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		// 获取标记为AspectJ的类
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		// 获取标记为AspectJ的name
		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
		// 验证
		validate(aspectClass);

		// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
		// so that it will only instantiate once.
		MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
				new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

		List<Advisor> advisors = new ArrayList<>();
		for (Method method : getAdvisorMethods(aspectClass)) {
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), 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()) {
			// 如果寻找到的增强器不为空而且又配置了增强延迟初始化,那么需要在首位加入同步实例化增强器,这个SyntheticInstantiationAdvisor会在切面方法例如类似@Before执行前调用aif.getAspectInstance()提前初始化切面
			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
			advisors.add(0, instantiationAdvisor);
		}

		// Find introduction fields. 获取DeclareParent注解
		for (Field field : aspectClass.getDeclaredFields()) {
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		return advisors;
	}

这一段逻辑还是简单明了的,首先获取被@Aspect注解的class对象,验证类是否合法,然后通过getAdvisorMethods(aspectClass)获取所有的切面方法,接着用getAdvisor()生成advisor,考虑到配置中可能存在将增强配置成延迟初始化,那么需要在首位加入同步实例化增强器以保证增强使用之前的实例化,最后是对 @DeclareParents 注解的获取。

获取所有的增强方法getAdvisorMethods().

	private List<Method> getAdvisorMethods(Class<?> aspectClass) {
		final List<Method> methods = new ArrayList<>();
		ReflectionUtils.doWithMethods(aspectClass, method -> {
			// Exclude pointcuts
			if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
				methods.add(method);
			}
		}, ReflectionUtils.USER_DECLARED_METHODS);
		methods.sort(METHOD_COMPARATOR);
		return methods;
	}

根据上面获取的method生成advisor,统一封装成InstantiationModelAwarePointcutAdvisorImpl,这是Advisor的内置实现。

1.首先看切点信息的获取

	@Override
	@Nullable
	public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
			int declarationOrderInAspect, String aspectName) {

		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

		// 切点信息的获取
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}

		// 根据切点信息生成增强器
		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}

我们看一下切点信息获取的方法getPointcut(),这里获取的标注了切面的注解的方法,生成一个AspectJExpressionPointcut设置表达式后返回。

	private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
        // 获取所有的标记了切面注解的方法,例如Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class等
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

        // 生成一个AspectJExpressionPointcut
		AspectJExpressionPointcut ajexp =
				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
        // 提取得到的注解中的表达式,如:
        // @Pointcut("execution(* io.codegitz.aop.demo.service.LoginService.login(..))")中的execution(* io.codegitz.aop.demo.service.LoginService.login(..))
		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
		if (this.beanFactory != null) {
			ajexp.setBeanFactory(this.beanFactory);
		}
		return ajexp;
	}

获取所有的标记了切面注解的方法AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod).

	private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
	
	protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
		for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
			AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
			if (foundAnnotation != null) {
				return foundAnnotation;
			}
		}
		return null;
	}

返回对象AspectJExpressionPointcut的构造函数如下,只是简单的赋值,没有特别的操作。

	public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
		this.pointcutDeclarationScope = declarationScope;
		if (paramNames.length != paramTypes.length) {
			throw new IllegalStateException(
					"Number of pointcut parameter names must match number of pointcut parameter types");
		}
		this.pointcutParameterNames = paramNames;
		this.pointcutParameterTypes = paramTypes;
	}

2.根据切点信息生成切面增强。

上面已经获取了切点信息,接下来就可以根据切点信息生成切面增强方法,所有的增强都由 Advisor的实现类 InstantiationModelAwarePointcutAdvisorImpl 统一封装的。

	public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		this.declaredPointcut = declaredPointcut;
		this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
		this.methodName = aspectJAdviceMethod.getName();
		this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
		this.aspectJAdviceMethod = aspectJAdviceMethod;
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
		this.aspectInstanceFactory = aspectInstanceFactory;
		this.declarationOrder = declarationOrder;
		this.aspectName = aspectName;

		if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			// Static part of the pointcut is a lazy type.
			Pointcut preInstantiationPointcut = Pointcuts.union(
					aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

			// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
			// If it's not a dynamic pointcut, it may be optimized out
			// by the Spring AOP infrastructure after the first evaluation.
			this.pointcut = new PerTargetInstantiationModelPointcut(
					this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
			this.lazy = true;
		}
		else {
			// A singleton aspect.
			this.pointcut = this.declaredPointcut;
			this.lazy = false;
            // 重点关注,对切面增强器进行初始化
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}

在封装的过程中,所有的信息都是进行简单的赋值,在赋值的同时会instantiatedAdvice进行初始化,因为不同的增强所体现的逻辑是不同的,比如 @Before("test()")@After("test()")标签的不同就是增强器增强的位置不同 ,所以就需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的增强器就是在 instantiateAdvice() 函数中实现的。

	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);
	}

这里会根据不同切面类型返回不同的实现。

	@Override
	@Nullable
	public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);

		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// 省略日志...

		AbstractAspectJAdvice springAdvice;

		// 根据不同的类型生成不同的增强
		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;
	}

从上面的代码可以看到,Spring会根据不同的类型生成不同的实现,其中不同类型间的实现会有些差异。AtBefore会对应AspectJMethodBeforeAdvice,而在 AspectJMethodBeforeAdvice中完成了增强方法的逻辑。 我们尝试分析几个常用的增强器实现。

MethodBeforeAdviceInterceptor前置拦截--最常用的拦截器之一

如果看了上一篇,会发现上一篇实现CGLIB代理用到的就是MethodBeforeAdviceInterceptor,这里再次出现,基本可以验证了我们文章开头猜测图的逻辑

看下类上注释,这个类就是包装了一个MethodBeforeAdvice,也就是我们上面说的AspectJMethodBeforeAdvice,然后把这个MethodBeforeAdviceInterceptor放到调用链里,在执行的时候会调用invoke()方法,这里会通过this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis())真实调用到切面增强方法,从而实现了在业务代码里嵌入切面的逻辑。

/**
 * Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}.
 * Used internally by the AOP framework; application developers should not need
 * to use this class directly.
 *
 * @author Rod Johnson
 * @see AfterReturningAdviceInterceptor
 * @see ThrowsAdviceInterceptor
 */
@SuppressWarnings("serial")
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

	private final MethodBeforeAdvice advice;

	/**
	 * Create a new MethodBeforeAdviceInterceptor for the given advice.
	 * @param advice the MethodBeforeAdvice to wrap
	 */
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		return mi.proceed();
	}

}

进入到AspectJMethodBeforeAdvice#before()方法,这一段逻辑没啥好说的,最后就是调用this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs)执行了切面增强方法。

	@Override
	public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
		invokeAdviceMethod(getJoinPointMatch(), null, null);
	}
	/**
	 * Invoke the advice method.
	 * @param jpMatch the JoinPointMatch that matched this execution join point
	 * @param returnValue the return value from the method execution (may be null)
	 * @param ex the exception thrown by the method execution (may be null)
	 * @return the invocation result
	 * @throws Throwable in case of invocation failure
	 */
	protected Object invokeAdviceMethod(
			@Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
			throws Throwable {

		return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
	}

执行增强方法。

	protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
		if (this.aspectJAdviceMethod.getParameterCount() == 0) {
			actualArgs = null;
		}
		try {
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
			// TODO AopUtils.invokeJoinpointUsingReflection
			// 激活增强方法
			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();
		}
	}

AspectJAfterAdvice后置拦截

后置增强与前置增强有稍许不一致的地方。 回顾之前讲过的前置增强,大致的结构是在拦截器链中放置 MethodBeforeAdviceInterceptor,而在MethodBeforeAdviceInterceptor中又放置了 AspectJMethodBeforeAdvice,并在调用 invoke 时首先串联调用。 但是在后置增强的时候却不一 样,没有提供中间的类,而是直接在拦截器链中使用了中间的AspectJAfterAdvice

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
            // 激活切面增强方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

AbstractAdvisorAutoProxyCreator返回可以应用的切面增强方法

上一小节ReflectiveAspectJAdvisorFactory获取Advisor的逻辑解析已经获取到了所有的切面方法增强,并且已经封装成统一的格式,但是这里返回的是所有的切面增强方法,并不一定适合当前的Bean,所以下一步我们需要找出合适的切面增强器,那么我们回到AbstractAdvisorAutoProxyCreator#findEligibleAdvisors()方法里

1641358486571

这里最难的一步findCandidateAdvisors()已经完成了,接下来是挑取出适合的增强器,也就是满足我们配置的通配符的增强器。

	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
            // 过滤已经得到的advisors
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

跟进findAdvisorsThatCanApply方法,

	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
            // 首先处理引介增强
			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;
	}

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

	/**
	 * Can the given advisor apply at all on the given class?
	 * This is an important test as it can be used to optimize
	 * out a advisor for a class.
	 * @param advisor the advisor to check
	 * @param targetClass class we're testing
	 * @return whether the pointcut can apply on any method
	 */
	public static boolean canApply(Advisor advisor, Class<?> targetClass) {
		return canApply(advisor, targetClass, false);
	}

	/**
	 * Can the given advisor apply at all on the given class?
	 * <p>This is an important test as it can be used to optimize out a advisor for a class.
	 * This version also takes into account introductions (for IntroductionAwareMethodMatchers).
	 * @param advisor the advisor to check
	 * @param targetClass class we're testing
	 * @param hasIntroductions whether or not the advisor chain for this bean includes
	 * any introductions
	 * @return whether the pointcut can apply on any method
	 */
	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		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.
			return true;
		}
	}

这段逻辑区分了IntroductionAdvisorPointcutAdvisor,然后再去执行不同的逻辑去匹配是否能执行。advisor是Spring Aop里面一个重要的概念,IntroductionAdvisorPointcutAdvisor其中的两个重要的实现,这两者有什么区别呢❓ 简单来说主要是粒度不一样,前者是作用来类上的,后者是作用在方法上,粒度更细,也更常用。更多advisor的概念和Spring的实现体系可以查看Spring Aop中advisor概念以及实现详解

总结

这一篇主要介绍了Spring Aop获取所有的切面增强方法的代码逻辑,总得来说思路是清晰的,从时序图看着比较明了,但是里面涉及的细节逻辑比较多,一篇下来代码量也很大,看起来可能会头疼。如果看着看着就晕车了,可以返回去看时序图,看当前是执行到了哪一步,做到心中有数。或者可以写个例子跟着代码调试,效果会更好。

再次回顾这个图,这篇文章回答了一部分问题,下一部分创建动态代理,老生常谈系列之Aop--Spring Aop源码解析(二)分析。

1641369374118

如果有人看到这里,那在这里老话重提。与君共勉,路漫漫其修远兮,吾将上下而求索。

posted @ 2022-01-05 16:06  Codegitz  阅读(228)  评论(0编辑  收藏  举报