spring aop 源碼核心流程分析

今天我們來看下 spring aop 模塊的核心流程。

1. 簡單的 spring aop 例子

先看一個 aop 例子。如下代碼,先定義一個切面

package example.scannable;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 打印日誌的切面
 */
@Component
@Aspect
public class MyLogAspect {

	@Pointcut("execution(* example.scannable.MyLogService.*(..))")
	public void pointCut() {
	}

	/**
	 * 方法前置通知
	 *
	 * @param joinPoint
	 */
	@Before(value = "pointCut()")
	public void methodBefore(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println(
				"執行目標方法【" + methodName + "】之前執行<前置通知>,入參" + Arrays.asList(joinPoint.getArgs()));
	}

	/**
	 * 方法後置通知
	 *
	 * @param joinPoint
	 */
	@After(value = "pointCut()")
	public void methodAfter(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println(
				"執行目標方法【" + methodName + "】之前執行<後置通知>,入參" + Arrays.asList(joinPoint.getArgs()));
	}

	/**
	 * 方法返回通知
	 *
	 * @param joinPoint
	 */
	@AfterReturning(value = "pointCut()")
	public void methodReturning(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println(
				"執行目標方法【" + methodName + "】之前執行<返回通知>,入參" + Arrays.asList(joinPoint.getArgs()));
	}

	/**
	 * 方法異常通知
	 *
	 * @param joinPoint
	 */
	@AfterThrowing(value = "pointCut()")
	public void methodAfterThrowing(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println(
				"執行目標方法【" + methodName + "】之前執行<異常通知>,入參" + Arrays.asList(joinPoint.getArgs()));

	}

}

這是一個自定義的切面,創建了方法切點、方法前置通知、方法後置通知、方法返回通知、方法異常通知。

我們再創建一個基礎的 service:

package example.scannable;

import org.springframework.stereotype.Service;

public interface MyLogService {

	String sayHello(String name);

}

package example.scannable;

import org.springframework.stereotype.Service;

@Service
public class MyLogServiceImpl implements MyLogService {

	@Override
	public String sayHello(String name) {
		String result = "hello " + name + "!";
		System.out.println(result);
		return result;
	}

}

這是一個基礎的類,它有一個方法,打印一個字符串,並返回參數。

我們再創建單元測試啓動類:

public class EnableAspectJAutoProxyTests {
	
  @Test
	public void withJdkProxy() {
		ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithJdkProxy.class);

		MyLogService fooService = ctx.getBean(MyLogService.class);

		fooService.sayHello("spring");

	}

	@ComponentScan("example.scannable")
	@EnableAspectJAutoProxy
	static class ConfigWithJdkProxy {
	}


}

執行結果如下:

執行目標方法【sayHello】之前執行<前置通知>,入參[spring]
hello spring! 
執行目標方法【sayHello】之前執行<返回通知>,入參[spring]
執行目標方法【sayHello】之前執行<後置通知>,入參[spring]

可以看到在執行 MyLogService 類的 sayHello 方法的前後,執行了切面類中的各個方法。

這個是一個 spring aop 切面的基本用法。

那它是如何做到的呢?下面我們進入 spring aop 模塊的源代碼中一探究竟!

2. EnableAspectJAutoProxy 註解

可以看到我們的配置類上使用了 @EnableAspectJAutoProxy 註解,它目就啓動了 aop 的切面功能。它是怎麼做到呢?我看看它的源代碼:

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

	/**
	 * 指示是否基於標準 Java 接口代理相反的,創建基於子類的 CGLIB 代理。默認是 false
	 *
	 * 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;

	/**
	 * 表明代理對象應該通過 AOP 框架以一個從線程本地化來恢復 AopContext 類變量的方式被暴露出來。
	 * 默認情況下是關閉的,即,不保證 AopContext 訪問能正常工作。
	 *
	 * 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 類導入到了 spring 容器中。繼續看它的源代碼:

package org.springframework.context.annotation;

import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;

/**
 * Registers an {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
 * AnnotationAwareAspectJAutoProxyCreator} against the current {@link BeanDefinitionRegistry}
 * as appropriate based on a given @{@link EnableAspectJAutoProxy} annotation.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 * @see EnableAspectJAutoProxy
 */
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) {

		// 註冊一個 AnnotationAwareAspectJAutoProxyCreator 類到 bean 工廠
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		// 解析 EnableAspectJAutoProxy 類註解
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				// 強制使用 CGLIB 代理
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				// 強制暴露代理對象
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}

我們發現,這個類是 ImportBeanDefinitionRegistrar 類型,即導入 bean 定義註冊器,看下它的類圖:

AspectJAutoProxyRegistrar

我在上一篇文章 spring ioc 容器核心流程分析中,講過這個類型,它是在 spring 容器 的 refresh() 刷新方法中的 invokeBeanFactoryPostProcessors() 方法中執行的,它是通過調用 org.springframework.context.annotation.ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry() 方法執行處理 bean 定義註冊器,最後調用到 org.springframework.context.annotation.ConfigurationClassPostProcessor 類的 postProcessBeanDefinitionRegistry() 方法中,接着,通過創建 ConfigurationClassParser 類,解析 @Configuration 類,最終處理 @Import 註解時,判斷 bean 的類型是否爲 ImportBeanDefinitionRegistrar 類型(即 AspectJAutoProxyRegistrar 類),然後實例化它並且保存到配置類 ConfigurationClass 上,最後再通過 ConfigurationClassBeanDefinitionReader 類型,配置類 bean 定義讀取器,去執行配置類中的導入 bean 註冊器的 registerBeanDefinitions() 方法。

這個方法中最主要的是 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 方法,看它的名字應該可以猜測到,它是往容器中註冊一個切面註解自動代理創建器。

	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
		// 創建一個切面註解自動代理創建器
		return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
	}

	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
		// 註冊一個 AnnotationAwareAspectJAutoProxyCreator 類
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

果然,就是註冊了一個 AnnotationAwareAspectJAutoProxyCreator 類到容器中。同樣看下它的類圖:

AnnotationAwareAspectJAutoProxyCreator

可以看到它實現了 BeanPostProcessor、InstantiationAwareBeanPostProcessor 接口。

其中它實現了 BeanPostProcessor 的 postProcessAfterInitialization() 方法,這個方法是在 createBean 創建 bean 方法中執行的,如下面的方法調用棧。

# 執行 AbstractAutoProxyCreator 類的實例化之前的後置處理方法
postProcessBeforeInstantiation(Class, String):257, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy), AbstractAutoProxyCreator.java
# 在實例化之前應用 bean 後置處理器
applyBeanPostProcessorsBeforeInstantiation(Class, String):1202, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# bean 實例化之前的解析
resolveBeforeInstantiation(String, RootBeanDefinition):1175, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# 委派到 createBean 方法
createBean(String, RootBeanDefinition, Object[]):550, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
lambda$doGetBean$0(String, RootBeanDefinition, Object[]):364, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
# 調用 ObjectFactory 個 getObject() 方法
getObject():-1, 424732838 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$384), Unknown Source
# 獲取單例
getSingleton(String, ObjectFactory):262, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support), DefaultSingletonBeanRegistry.java
# 獲取 bean
doGetBean(String, Class, Object[], boolean):361, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
# 獲取 bean
getBean(String):218, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
# 預處理單例實例
preInstantiateSingletons():957, DefaultListableBeanFactory (org.springframework.beans.factory.support), DefaultListableBeanFactory.java
# 實例化剩餘單例
finishBeanFactoryInitialization(ConfigurableListableBeanFactory):982, AbstractApplicationContext (org.springframework.context.support), AbstractApplicationContext.java
# 刷新方法
refresh():613, AbstractApplicationContext (org.springframework.context.support), AbstractApplicationContext.java
...省略

它的方法具體流程,我們稍後詳細再看。

還有,它實現了 InstantiationAwareBeanPostProcessor 接口的 postProcessBeforeInstantiation() 方法,對 bean 實例化之前執行處理操作。它是在創建 bean 之後,對 bean 進行初始化的時候調用的,如下方法的調用棧:

# 執行 AbstractAutoProxyCreator 的 postProcessAfterInitialization 方法
postProcessAfterInitialization(Object, String):305, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy), AbstractAutoProxyCreator.java
# 應用 bean 初始化後的後置處理
applyBeanPostProcessorsAfterInitialization(Object, String):468, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# 初始化 bean
initializeBean(String, Object, RootBeanDefinition):1923, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# 創建 bean
doCreateBean(String, RootBeanDefinition, Object[]):654, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# 委派到 createBean 方法
createBean(String, RootBeanDefinition, Object[]):562, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), 
...同上...
doGetBean(String, Class, Object[], boolean):361, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
getBean(String):218, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
preInstantiateSingletons():957, DefaultListableBeanFactory (org.springframework.beans.factory.support), DefaultListableBeanFactory.java
finishBeanFactoryInitialization(ConfigurableListableBeanFactory):982, AbstractApplicationContext (org.springframework.context.support), AbstractApplicationContext.java
refresh():613, AbstractApplicationContext (org.springframework.context.support), AbstractApplicationContext.java
...省略無關的調用

我們重點看下這兩個方法。

3. bean 實例化之前的後置處理

下面,我們開始着重看 AbstractAutoProxyCreator#postProcessBeforeInstantiation 這個方法,源碼附上:

	/**
	 * 實例化之前的後置處理,創建代理對象
	 *
	 * @param beanClass the class of the bean to be instantiated
	 * @param beanName  the name of the bean
	 * @return
	 */
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			// 判斷是否基礎類,是否應該跳過,這裏進行創建增強器,並放入緩存中
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// 如果我們一個自定義的目標源,那就創建代理對象。
		// 禁止目標 bean 不必要的初始化。
		// 這個目標源將會以自定義的方式處理目標實例。
		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			// 獲取類的增強器
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			// 創建代理對象,這裏決定創建 jdk 代理或者是 cglib 代理對象
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			// 放入緩存
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}

postProcessBeforeInstantiation 這個方法的主要的邏輯是:

  1. 判斷 bean 是否爲基礎的類;
  2. 通過獲取容器中所有的增強器,並且加入到緩存中,判斷增強器是否應該被跳過;
  3. 如果有自定義的目標源,那就創建代理對象並返回對象,沒有的話則返回 null;

我們看下 isInfrastructureClass() 方法,判斷是否爲基礎類,我們看下它的實現:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#isInfrastructureClass

  // 判斷是否爲基礎類
  protected boolean isInfrastructureClass(Class<?> beanClass) {
		boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
				Pointcut.class.isAssignableFrom(beanClass) ||
				Advisor.class.isAssignableFrom(beanClass) ||
				AopInfrastructureBean.class.isAssignableFrom(beanClass);
		if (retVal && logger.isTraceEnabled()) {
			logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
		}
		return retVal;
	}

這個方法的邏輯是,判斷這個類是不是一個 Advice、Pointcut、Advisor、AopInfrastructureBean 類型;

3.1 shouldSkip 是否需要跳過

下面看重點的 shouldSkip 方法:org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip

	/**
	 * 判斷是否跳過指定的類型和 bean
	 *
	 * @param beanClass the class of the bean
	 * @param beanName  the name of the bean
	 * @return
	 */
	@Override
	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
		// 找到候選的增強器,創建的時候也把它們放入緩存中
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor &&
					((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
				return true;
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

3.1.1 findCandidateAdvisors 查找候選的增強器

這裏邊是先找候選的增強器,繼續看看它的邏輯:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

	@Override
	protected List<Advisor> findCandidateAdvisors() {
		// spring tx 事務模塊實現了 Advisor 接口
		// 從 bean 工廠中找 Advisor 類型的候選 bean
		// Add all the Spring advisors found according to superclass rules.
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
			// 使用切面增強器構建器,進行構建增強器
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

先調用父類的方法,然後在調用自己的構建切面增強器。看看父類的方法是什麼樣的邏輯:

	/**
	 * 找使用了自動代理的候選增強器
	 * Find all candidate Advisors to use in auto-proxying.
	 * @return the List of candidate Advisors
	 */
	protected List<Advisor> findCandidateAdvisors() {
		Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
		// 使用增強器恢復工具類去找增強器
		return this.advisorRetrievalHelper.findAdvisorBeans();
	}


org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
  
  	/**
	 * 從當前 bean 工廠中查找合格的增強器 beans,忽略工廠 bean 和當前正被創建的 bean
	 *
	 * Find all eligible Advisor beans in the current bean factory,
	 * ignoring FactoryBeans and excluding beans that are currently in creation.
	 * @return the list of {@link org.springframework.aop.Advisor} beans
	 * @see #isEligibleBean
	 */
	public List<Advisor> findAdvisorBeans() {
		// 找增強器的 bean 名稱
		// Determine list of advisor bean names, if not cached already.
		String[] advisorNames = this.cachedAdvisorBeanNames;
		if (advisorNames == null) {
			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the auto-proxy creator apply to them!
			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) {
			// 是否一個合格的 bean
			if (isEligibleBean(name)) {
				// 顧慮當前被創建的 bean
				if (this.beanFactory.isCurrentlyInCreation(name)) {
					if (logger.isTraceEnabled()) {
						logger.trace("Skipping currently created advisor '" + name + "'");
					}
				}
				else {
					try {
						// 從 bean 工廠中查找 Advisor 類型的 bean
						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());
								}
								// Ignore: indicates a reference back to the bean we're trying to advise.
								// We want to find advisors other than the currently created bean itself.
								continue;
							}
						}
						throw ex;
					}
				}
			}
		}
		return advisors;
	}

這裏的主要做的事情就是從 bean 工廠中獲取 Advisor 類型的 beans 返回。spring tx 模塊的源碼,就是在這裏進行查找的。

3.1.2 buildAspectJAdvisors 構建切面增強器

接着回來看下 this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 這個方法,它實際上是 org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors 的方法:

	/**
	 * 從當前 bean 工廠中查找 AspectJ 註解的切面,返回一個 spring aop 增強器的列表。
	 * 爲每個切面的 advice 方法創建一個 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<>();
					// 從 bean 工廠中找出全部的 bean 名稱
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					for (String beanName : beanNames) {
						if (!isEligibleBean(beanName)) {
							continue;
						}
						// 我們需要小心不要讓這些 bean 過早的實例化,這種情況下它們將會被 spring 容器緩存,但不會被編織。
						// 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, 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);
								// 獲取全部的增強器,重要的方法
								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;
	}

	@Override
	public boolean isAspect(Class<?> clazz) {
		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
	}

	private boolean hasAspectAnnotation(Class<?> clazz) {
		return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
	}

	/**
	 * We need to detect this as "code-style" AspectJ aspects should not be
	 * interpreted by Spring AOP.
	 */
	private boolean compiledByAjc(Class<?> clazz) {
		// The AJTypeSystem goes to great lengths to provide a uniform appearance between code-style and
		// annotation-style aspects. Therefore there is no 'clean' way to tell them apart. Here we rely on
		// an implementation detail of the AspectJ compiler.
		for (Field field : clazz.getDeclaredFields()) {
			if (field.getName().startsWith(AJC_MAGIC)) {
				return true;
			}
		}
		return false;
	}



這裏主要做了幾件事情:

  1. 遍歷所有的 bean;
  2. 通過 org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect 方法判斷類是否一個切面,使用 @Aspect 註解標記的類;
  3. 根據bean 的 scope 類型創建對應的切面實例工廠,通過工廠獲取增強器。單例類型對應的工廠是 BeanFactoryAspectInstanceFactory,否則使用 PrototypeAspectInstanceFactory 工廠;
  4. 收集把所有的增強器,並且將它們添加到緩存中,最後返回增強器集合。

其中第 3 步中,兩個切面實例工廠都是繼承了 org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory 類,它的 getAdvisors 如下:

	/**
	 * 獲取增強器
	 *
	 * @param aspectInstanceFactory the aspect instance factory
	 *                              (not the aspect instance itself in order to avoid eager instantiation)
	 * @return
	 */
	@Override
	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		// 切面類型
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		// 切面名稱
		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
		// 校驗
		validate(aspectClass);

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

		List<Advisor> advisors = new ArrayList<>();
		// 獲取類上的所有增強器方法
		for (Method method : getAdvisorMethods(aspectClass)) {
			// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
			// to getAdvisor(...) to represent the "current position" in the declared methods list.
			// However, since Java 7 the "current position" is not valid since the JDK no longer
			// returns declared methods in the order in which they are declared in the source code.
			// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
			// discovered via reflection in order to support reliable advice ordering across JVM launches.
			// Specifically, a value of 0 aligns with the default value used in
			// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
			// 開始獲取增強器,增強器實現了方法攔截器接口,用於執行時進行調用
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		// If it's a per target aspect, emit the dummy instantiating aspect.
		if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
			advisors.add(0, instantiationAdvisor);
		}

		// 查找介紹的字段
		// Find introduction fields.
		for (Field field : aspectClass.getDeclaredFields()) {
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		return advisors;
	}


主要的邏輯爲:

  1. 獲取切面的類型、名稱,進行校驗;
  2. 獲取切面類的所有的除了 @Pointcut 註解標記的所有方法,並進行排序;
  3. 根據方法獲取切面註解(Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),然後創建切點表達式端點類 AspectJExpressionPointcut,最後創建一個實例化模型切點增強器實例 InstantiationModelAwarePointcutAdvisorImpl 返回
  4. 獲取切面類上聲明的字段,過濾出標記有 @DeclareParents 註解的字段,創建 DeclareParentsAdvisor 類返回。

4. bean 初始化之後的後置處理

接着,該看 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization 類方法了:

	/**
	 * 初始化之後的後置處理,如果 bean 被標識爲被子類代理的類,那就用配置的攔截器創建一個代理對象。
	 *
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 進行包裝實例化
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

它又去調用了 wrapIfNecessary 方法:

	/**
	 * 必要的時候包裝給定的 bean,比如是否需要被代理。
	 *
	 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
	 * @param bean the raw bean instance
	 * @param beanName the name of the bean
	 * @param cacheKey the cache key for metadata access
	 * @return a proxy wrapping the bean, or the raw bean instance as-is
	 */
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 判斷是否基礎對象,或者允許跳過
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// 創建代理對象,如果有增強器
		// Create proxy if we have advice.
		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;
	}

它的主要流程:

  1. 判斷bean 是否基礎類,是否應該跳過(這一步已經在上面的 postProcessBeforeInstantiation 方法執行過了);
  2. 執行 getAdvicesAndAdvisorsForBean() 方法,爲目標 bean 獲取的通知和增強器;
  3. 增強器不爲空,則代理創建代理對象;
  4. 返回創建的代理對象;

我們重點看下 getAdvicesAndAdvisorsForBean 獲取通知和增強器邏輯和創建代理對象邏輯。

4.1 getAdvicesAndAdvisorsForBean 獲取通知和增強器

它是實現在 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean:

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

又調用了方法 findEligibleAdvisors() 方法:

	/**
	 * Find all eligible Advisors for auto-proxying this class.
	 * @param beanClass the clazz to find advisors for
	 * @param beanName the name of the currently proxied bean
	 * @return the empty List, not {@code null},
	 * if there are no pointcuts or interceptors
	 * @see #findCandidateAdvisors
	 * @see #sortAdvisors
	 * @see #extendAdvisors
	 */
	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;
	}

做了三件事:

  1. 執行 findCandidateAdvisors() 查找候選增強器(這一步同樣也是在上面的 3.1.1 節講過了);
  2. 執行 findAdvisorsThatCanApply() 繼續查找能應用的增強器;
  3. 執行 extendAdvisors() 擴展增強器;
  4. 返回可以用的增強器。

4.1.1 findAdvisorsThatCanApply 查找可以應用的增強器

我們看下 org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply 方法:

	/**
	 * 從給定的類中選擇一個候選增強器,這個列表要適用於給定的類
	 *
	 * Determine the sublist of the {@code candidateAdvisors} list
	 * that is applicable to the given class.
	 * @param candidateAdvisors the Advisors to evaluate
	 * @param clazz the target class
	 * @return sublist of Advisors that can apply to an object of the given class
	 * (may be the incoming List as-is)
	 */
	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;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

這裏主要執行了 canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) 方法:

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

這裏判斷增強器的類型,一般是 InstantiationModelAwarePointcutAdvisorImpl 類型,它實現了 PointcutAdvisor 接口,執行 canApply(pca.getPointcut(), targetClass, hasIntroductions) 方法:

	/**
	 * 給定的切點可以全部應用到這個類上嗎?這是一個非常重要的測試,因爲它用於優化一個類的切點。
。	 *
	 * Can the given pointcut apply at all on the given class?
	 * <p>This is an important test as it can be used to optimize
	 * out a pointcut for a class.
	 * @param pc the static or dynamic pointcut to check
	 * @param targetClass the class to test
	 * @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(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		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;
		}

		// 獲取目標類的 Class 類型
		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)) {
					return true;
				}
			}
		}

		return false;
	}

這裏主要做了一下幾件事情:

  1. 獲取增強器中的切點的方法匹配器;
  2. 獲取目標類的原始類、所有的接口信息;
  3. 遍歷類和接口,獲取其上的聲明的方法;
  4. 根據匹配與方法機型匹配;
  5. 返回匹配結果。

4.1.2 extendAdvisors 擴展增強器

對應的是 org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#extendAdvisors 方法:

	/**
	 * Add an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
	 * <p>This additional advice is needed when using AspectJ pointcut expressions
	 * and when using AspectJ-style advice.
	 */
	@Override
	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
		// 如果需要的話,設置增強器調用器鏈,添加一個暴露方法執行器的執行攔截器
		AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
	}

繼續看它的實現:

	/**
	 * Add special advisors if necessary to work with a proxy chain that contains AspectJ advisors:
	 * concretely, {@link ExposeInvocationInterceptor} at the beginning of the list.
	 * <p>This will expose the current Spring AOP invocation (necessary for some AspectJ pointcut
	 * matching) and make available the current AspectJ JoinPoint. The call will have no effect
	 * if there are no AspectJ advisors in the advisor chain.
	 * @param advisors the advisors available
	 * @return {@code true} if an {@link ExposeInvocationInterceptor} was added to the list,
	 * otherwise {@code false}
	 */	
	public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
		// Don't add advisors to an empty list; may indicate that proxying is just not required
		if (!advisors.isEmpty()) {
			boolean foundAspectJAdvice = false;
			for (Advisor advisor : advisors) {
				// Be careful not to get the Advice without a guard, as this might eagerly
				// instantiate a non-singleton AspectJ aspect...
				if (isAspectJAdvice(advisor)) {
					foundAspectJAdvice = true;
					break;
				}
			}
			if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
				// 添加一個暴露執行的攔截器
				advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
				return true;
			}
		}
		return false;
	}

這個方法的邏輯是:

  1. 先從所有的增強器中一個切面通知;
  2. 判斷是否找到,並且這些增強器其中不包含 ExposeInvocationInterceptor.ADVISOR 常量;
  3. 如果符合條件,那麼添加 ExposeInvocationInterceptor.ADVISOR 常量,並且把它放入這些增強器的首尾。

4.2 createProxy 創建代理對象

接着看 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy 創建代理對象方法:

	/**
	 * 爲給定的 bean 創建一個代理對象
	 *
	 * Create an AOP proxy for the given bean.
	 * @param beanClass the class of the bean
	 * @param beanName the name of the bean
	 * @param specificInterceptors the set of interceptors that is
	 * specific to this bean (may be empty, but not null)
	 * @param targetSource the TargetSource for the proxy,
	 * already pre-configured to access the bean
	 * @return the AOP proxy for the bean
	 * @see #buildAdvisors
	 */
	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()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		// 綁定增強器
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		// 自定義配置代理工廠,由用戶自己實現其方法
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// 創建代理對象
		return proxyFactory.getProxy(getProxyClassLoader());
	}

這裏主要進行的邏輯:

  1. 創建一個代理工廠 ProxyFactory;
  2. 設置代理工廠屬性,綁定增強器;
  3. 通過代理工廠來創建代理對象。

4.2.1 創建 AOP 代理對象

代理工廠創建代理對象 org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader):

	public Object getProxy(@Nullable ClassLoader classLoader) {
		// 創建一個 Aop 代理,通過 DefaultAopProxyFactory 來創建一個 aop 代理,來獲取代理對象
		return createAopProxy().getProxy(classLoader);
	}

它會創建一個 aop 代理:

/**
 * 子類應該調用這個來返回一個新的 AOP 代理,不應該用 this 作爲參數來創建一個 AOP 代理對象
 *
 * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
 * create an AOP proxy with {@code this} as an argument.
 */
protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   // 通過代理工廠創建代理類
   return getAopProxyFactory().createAopProxy(this);
}

然後會獲取一個 aop 代理工廠來創建 aop 代理:org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy

	/**
	 * 創建代理對象
	 *
	 * @param config the AOP configuration in the form of an
	 *               AdvisedSupport object
	 * @return
	 * @throws AopConfigException
	 */
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!IN_NATIVE_IMAGE &&
				(config.isOptimize() || config.isProxyTargetClass() || 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)) {
				// 代理對象是一個接口,或者它是一個 jdk 自帶的 Proxy 類,那就創建 jdk 的動態代理對象
				return new JdkDynamicAopProxy(config);
			}
			// 否則就創建一個 cglib 代理對象
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

這裏可以看到它會根據條件創建 jdk 代理或者 cglib 代理:

  • 目標類是一個接口或者目標類已經是一個jdk原生的代理對象(Proxy.class 之類),那麼就創建 JdkDynamicAopProxy 類對象;
  • 否則創建一個 ObjenesisCglibAopProxy 類型對象返回。

4.3 JdkDynamicAopProxy 創建代理對象

我們重點看下 JdkDynamicAopProxy 代理對象的實現。它的 getProxy 方法如下:

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
    // 使用 JDK 自帶的動態代理對象進行代理
		return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
	}

看到這個,是不是感覺非常熟悉,用的就是 jdk 自身的動態代理 API。通過調用 Proxy 的 newProxyInstance() 方法,來創建一個動態代理對象,其中這個方法的第三個參數類型是一個 InvocationHandler 類型,傳遞的實例就是 JdkDynamicAopProxy 類實例本身。

Proxy 動態代理對象創建代理對象的時候,實際上是使用到了 java.lang.reflect.ProxyGenerator#generateClassFile 方法來生成目標類實例,它是在內存中通過直接寫入字節碼對應的數據。

我們來看看 JdkDynamicAopProxy 它實現的 InvocationHandler 接口的 invoke() 方法:

	/**
	 * 執行代理
	 *
	 * Implementation of {@code InvocationHandler.invoke}.
	 * <p>Callers will see exactly the exception thrown by the target,
	 * unless a hook method throws an exception.
	 */
	@Override
	@Nullable
	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;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// equals 方法
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			// 如果設置了暴露代理對象,就將其放入當前線程本地化中
			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// 獲取攔截器和動態攔截器通知
			// Get the interception chain for this method.
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// 創建一個方法執行器
				// We need to create a method invocation...
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				// 執行方法,重點方法,使用了責任鏈調用模式
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				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;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

我們梳理下它的流程:

  1. 對一些基礎方法和 DecoratingProxy 類型、Advised 類型直接返回,比如 equals、hashCode等;
  2. 如果設置了暴露代理對象,就將其放入當前線程本地化中;
  3. 獲取攔截器和動態攔截器通知(非常重要的方法);org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
  4. 創建一個方法執行器 ReflectiveMethodInvocation,執行方法(非常重要的方法,內部使用了責任鏈調用模式);
  5. 返回生成的代理對象。

4.3.1 獲取攔截器和動態攔截通知

這個邏輯對應上面 invoke 流程中的第 3 步,是非常重要的方法。先看下它的源碼:org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice

	/**
	 * 從給定的方法和目標類中,根據增強器的通知來創建對應的攔截器和冬天攔截器通知。
	 *
	 * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects
	 * for the given method, based on this configuration.
	 * @param method the proxied method
	 * @param targetClass the target class
	 * @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
	 */
	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;
	}

它又繼續調用了增強器鏈工廠的方法:org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

	/**
	 * 獲取增強器的通知,並且將它轉成方法攔截器
	 *
	 * @param config      the AOP configuration in the form of an Advised object
	 * @param method      the proxied method
	 * @param targetClass the target class (may be {@code null} to indicate a proxy without
	 *                    target object, in which case the method's declaring class is the next best option)
	 * @return
	 */
	@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// 增強器適配器註冊器
		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		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) {
				// 基本上屬於 InstantiationModelAwarePointcutAdvisorImpl 這個類
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				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);
					}
					// 判斷方法和切點是否匹配
					if (match) {
						// 從註冊器中獲取增強的方法攔截器
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							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;
	}

這個可是最核心的方法了,梳理下它的調用流程:

  1. 獲取一個增強器適配器註冊表對象 AdvisorAdapterRegistry,實際上是一個 DefaultAdvisorAdapterRegistry 類型的對象;
  2. 獲取所有的增強器進行遍歷;
  3. 根據增強器所屬類型(主要是 PointcutAdvisor 類型),進行判斷是否匹配目標(獲取切點上的方法匹配器與目標方法進行匹配);
  4. 從增強器適配器註冊表 DefaultAdvisorAdapterRegistry 中,根據增強器來獲取攔截器;
  5. 返回攔截器集合。

4.3.1.1 從增強器適配器註冊表中獲取攔截器

我們看下第 4 步,從增強器適配器註冊表中獲取攔截器:org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#getInterceptors

	/**
	 * 從給定的增強器中獲取方法攔截器
	 *
	 * @param advisor the Advisor to find an interceptor for
	 * @return
	 * @throws UnknownAdviceTypeException
	 */
	@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		// 獲取增強器上的通知
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			// 方法攔截器接口,環繞通知、後置通知、異常通知
			interceptors.add((MethodInterceptor) advice);
		}
		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]);
	}


	// 增強器適配器
	private final List<AdvisorAdapter> adapters = new ArrayList<>(3);


	/**
	 * 創建一個增強器適配器註冊器,註冊已知的適配器。
	 *
	 * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
	 */
	public DefaultAdvisorAdapterRegistry() {
		// 註冊前置通知適配器
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		// 註冊返回通知適配器
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		// 註冊異常通知適配器
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}

	@Override
	public void registerAdvisorAdapter(AdvisorAdapter adapter) {
		this.adapters.add(adapter);
	}

那麼它的流程是:

  1. 獲取增強器上的通知;
  2. 判斷通知是否屬於 MethodInterceptor 類型,屬於就直接放入集合保存起來;
  3. 遍歷註冊表中的所有的適配器(MethodBeforeAdviceAdapter 前置通知適配器、AfterReturningAdviceAdapter 返回通知適配器、ThrowsAdviceAdapter 異常通知適配器),判斷通知是否支持,支持的話就從對應的適配器中獲取攔截器(分別對應 MethodBeforeAdviceInterceptor 前置通知攔截器、AfterReturningAdviceInterceptor 後置通知攔截器、ThrowsAdviceInterceptor 異常通知攔截器)保存到集合;
  4. 返回保存的攔截器集合。

4.3.2 ReflectiveMethodInvocation 方法執行器

下面,我們該看執行方法的邏輯了。它是通過創建一個方法執行器 ReflectiveMethodInvocation 對象,看它的 proceed() 方法:

	/**
	 * 執行方法調用
	 *
	 * @return
	 * @throws Throwable
	 */
	@Override
	@Nullable
	public Object proceed() throws Throwable {
		// 從索引爲 -1 開始調用
		// 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) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			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);
		}
	}

它的邏輯是:

  1. 判斷當前 currentInterceptorIndex 變量(從 -1 開始)是否等於攔截器鏈長度減一的值,如果符合,則執行 invokeJoinpoint() 方法,真正執行目標方法調用(通過反反射調用);
  2. 使用 currentInterceptorIndex 變量遞增,從攔截器鏈中獲取攔截器;
  3. 執行攔截器的 invoke 方法,並傳入當前對象(攔截器中會根據它的類型來決定)。

先看下 MethodInterceptor 攔截器接口的實現圖:

MethodInterceptor

上面的方法攔截器實現依次是:前置通知、異常通知、返回通知、後置通知、環繞通知攔截器。

這裏的調用流程非常有必要打斷點走一遍,在目標方法 example.scannable.MyLogService#sayHello 上打斷點,看下它的方法調用棧:

# 最後執行目標方法 MyLogServiceImpl 的 sayHello 方法
sayHello(String):11, MyLogServiceImpl (example.scannable), MyLogServiceImpl.java
invoke0(Method, Object, Object[]):-1, NativeMethodAccessorImpl (jdk.internal.reflect), NativeMethodAccessorImpl.java
invoke(Object, Object[]):62, NativeMethodAccessorImpl (jdk.internal.reflect), NativeMethodAccessorImpl.java
invoke(Object, Object[]):43, DelegatingMethodAccessorImpl (jdk.internal.reflect), DelegatingMethodAccessorImpl.java
# 執行 Method 的的 invoke 方法,反射
invoke(Object, Object[]):566, Method (java.lang.reflect), Method.java
# 最後執行 AopUtils類的 invokeJoinpointUsingReflection 方法
invokeJoinpointUsingReflection(Object, Method, Object[]):359, AopUtils (org.springframework.aop.support), AopUtils.java
# 最後執行 ReflectiveMethodInvocation 類的 invokeJoinpoint 方法
invokeJoinpoint():217, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():177, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第三個攔截器 AspectJAfterThrowingAdvice 異常通知攔截器的 invoke 方法
invoke(MethodInvocation):67, AspectJAfterThrowingAdvice (org.springframework.aop.aspectj), AspectJAfterThrowingAdvice.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第三個攔截器 AfterReturningAdviceInterceptor 返回通知攔截器的 invoke 方法
invoke(MethodInvocation):58, AfterReturningAdviceInterceptor (org.springframework.aop.framework.adapter), AfterReturningAdviceInterceptor.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第二個攔截器 AspectJAfterAdvice 後置通知攔截器的 invoke 方法
invoke(MethodInvocation):52, AspectJAfterAdvice (org.springframework.aop.aspectj), AspectJAfterAdvice.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第二個攔截器 MethodBeforeAdviceInterceptor 前置通知攔截器的 invoke 方法
invoke(MethodInvocation):60, MethodBeforeAdviceInterceptor (org.springframework.aop.framework.adapter), MethodBeforeAdviceInterceptor.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第一個攔截器 ExposeInvocationInterceptor 的 invoke 方法
invoke(MethodInvocation):99, ExposeInvocationInterceptor (org.springframework.aop.interceptor), ExposeInvocationInterceptor.java
# 執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行 JdkDynamicAopProxy 的 invoke 方法
invoke(Object, Method, Object[]):222, JdkDynamicAopProxy (org.springframework.aop.framework), JdkDynamicAopProxy.java
# 執行代理對象 Proxy 的 sayHello 方法
sayHello(String):-1, $Proxy50 (com.sun.proxy), Unknown Source
aspectIsApplied1(ApplicationContext):67, EnableAspectJAutoProxyTests (org.springframework.context.annotation), EnableAspectJAutoProxyTests.java
# 調用 EnableAspectJAutoProxyTests 測試類的 withJdkProxy 方法
withJdkProxy():44, EnableAspectJAutoProxyTests (org.springframework.context.annotation), EnableAspectJAutoProxyTests.java
...省略無關調用棧

從上面的方法執行調用鏈以及方法執行源代碼看,它是使用了責任鏈模式 + 遞歸的方式進行調用,先從攔截器鏈中一個個的執行攔截器,最後再調用目標方法,形成一個攔截器調用鏈棧,最後執行完目標方法之後,依次返回攔截器執行剩餘的方法邏輯,最後結束。

這個過程在很多地方都用到了,比如 Java web 中的 filter 過濾器鏈,和 spring mvc 中的方法攔截器鏈,都是同一個套路。web 服務器 Tomcat 中每次接收處理一個請求時,也是會創建了一個 org.apache.catalina.core.ApplicationFilterChain 過濾器鏈,這過濾器鏈中也是持有一組過濾器,然後通過一個變量從 0 開始,遞增的獲取過濾器,然後進行執行目標方法。

5. 總結

以上就是 spring aop 的源碼核心流程,我們來稍微的回顧下:

  1. 通過在類上使用 @EnableAspectJAutoProxy 註解,開啓 spring aop 功能;
  2. 這個註解引入了 AnnotationAwareAspectJAutoProxyCreator 類,它是一個 bean 後置處理器,分別主要是負責在創建 bean 時進行解析其類上的切面、通知信息,以及通過使用 jdk 動態代理或者 cglib 動態代理來創建目標;
  3. 然後在執行一個動態代理的 bean 的方法時,通過將解析出來的切面、切點來創建對應的方法攔截器鏈,以遞歸 + 責任鏈的方式執行攔截器和目標方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章