Spring源碼分析十一:@AspectJ方式的AOP

一、前言

本文是筆者閱讀Spring源碼的記錄文章,由於本人技術水平有限,在文章中難免出現錯誤,如有發現,感謝各位指正。在閱讀過程中也創建了一些衍生文章,衍生文章的意義是因爲自己在看源碼的過程中,部分知識點並不瞭解或者對某些知識點產生了興趣,所以爲了更好的閱讀源碼,所以開設了衍生篇的文章來更好的對這些知識點進行進一步的學習。

全集目錄:Spring源碼分析:全集整理


本文衍生篇:
Spring 源碼分析衍生篇九 : AOP源碼分析 - 基礎篇

本文後篇:
Spring源碼分析十二:@AspectJ方式的AOP 之 getAdvicesAndAdvisorsForBean

二、簡介

Aop 即面向切面編程,而 Aspect 是Aop 思想的一種實現。
並不是所有的AOP框架都相同,它們在連接點模型上可能有強弱之分,有些允許在字段修飾符級別的應用通知,有些只支持方法調用相關的連接點。需要注意的是 Spring 只支持方法級別的連接點。

Spring 提供了4種類型的AOP支持

  • 基於代理的經典Spring Aop
  • 純Pojo切面
  • @AspectJ註解驅動的切面
  • 注入式的Aspectj的切面

前三種都是Spring Aop 實現的變體,Spring Aop 構建在動態代理之上,因此Spring 對Aop的支持侷限於方法攔截。

本文分析的是 基於 @AspectJ 註解的 Aop 源碼。

1. Spring Aop 和 AspectJ 的關係

AspectJ 是一套AOP框架,是對java語言語法和語義的擴展,所以他自己提供了一套關鍵字,這也就是說,如果在沒有安裝 AspectJ的情況下,是無法使用 AspectJ 的。而Spring Aop 依賴的是Spring,僅僅能做到方法級別的攔截。所以在Spring中使用 @AspectJ 註解實現的AOP 功能,其底層實現還是 Spring Aop。


2. @ApsectJ 的啓用 - @EnableAspectJAutoProxy

在使用AspectJ AOP 功能時,我們需要使用註解 @EnableAspectJAutoProxy(proxyTargetClass = true) 來開啓Aop 功能。那麼我們的分析入口自然是從這個註解開始。

但實際上,啓用AOP功能並不需要我們手動去聲明。因爲在只要我們引入了 SpringAop 對應的依賴,Spring就自動幫我們啓用 Aop功能。其原因在 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration 類中,如下,Spring 會將 AopAutoConfiguration 加載作爲配置類,其內部類也會加載,默認加載 CglibAutoProxyConfigurationCglibAutoProxyConfiguration 上有 @EnableAspectJAutoProxy(proxyTargetClass = true) 註解,也就達到了默認開始AOP的功能。

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		static class CglibAutoProxyConfiguration {

		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	static class ClassProxyingConfiguration {

		ClassProxyingConfiguration(BeanFactory beanFactory) {
			if (beanFactory instanceof BeanDefinitionRegistry) {
				BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
		}

	}

}

不過我們仍舊可以知道,AOP的功能入口在於@EnableAspectJAutoProxy 註解。

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

	boolean proxyTargetClass() default false;

	boolean exposeProxy() default false;

}

分析了這麼久的源碼,從上面我們可以看到 @EnableAspectJAutoProxy 註解 中使用了 @Import(AspectJAutoProxyRegistrar.class) 註解引入了AspectJAutoProxyRegistrar 類,因此我們下面來看看 AspectJAutoProxyRegistrar 類的實現。

二、 AspectJAutoProxyRegistrar

在這裏插入圖片描述
AspectJAutoProxyRegistrar 實現了 ImportBeanDefinitionRegistrar 接口,那麼我們自然要看看他的registerBeanDefinitions 方法了。(Spring 在 ConfigurationClassPostProcessor 中完成了對 ImportBeanDefinitionRegistrar 接口的處理,主要功能還是將BeanDefinition注入到Spring容器中。具體可以看 :Spring 源碼分析衍生篇七 :ConfigurationClassPostProcessor 上篇)。

	/**
	 * 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) {
		// 如有必要,註冊Aspect J註釋自動代理創建器
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
		// 獲取 @EnableAspectJAutoProxy 註解
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			// 解析 proxyTargetClass 屬性
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			//  解析 exposeProxy 屬性
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

從上面代碼我們可以看到,registerBeanDefinitions 方法最主要的功能就是自動代理創建器的註冊。(所謂的自動代理創建器,顧名思義就是可以用來自動創建代理的"機器",可以簡單理解成Spring 封裝的一個創建代理對象的工具類,具有多種實現方式,這個下面會講。這裏使用AOP的實現方式,因此我們來看他的註冊過程, 即 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 方法 。


其中 registerAspectJAnnotationAutoProxyCreatorIfNecessary 方法在經歷數次跳轉後最終調用了 AopConfigUtils#registerOrEscalateApcAsRequired 方法。

上面我們說到自動代理創建器有多種實現方式,但是實際使用只能選擇其中一種,所以需要根據優先級來判斷使用哪一種。


	public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";

	private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

	static {
		// Set up the escalation list...
		// 事務使用
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		// Spring aop 使用
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
	}
			
	// 這裏的 cls 是 AnnotationAwareAspectJAutoProxyCreator.class
	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所對應的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;
	}

	...
	// 可以看到,所謂的優先級順序實際上是在 APC_PRIORITY_LIST 集合的順序
	public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			// 設置 proxyTargetClass 屬性
			definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
		}
	}
	
	...
	
	public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			// 設置 exposeProxy 屬性
			definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
		}
	}

這裏可以看到,整體是註冊了一個beanName爲“org.springframework.aop.config.internalAutoProxyCreator” 的bean,Bean 類型爲 AnnotationAwareAspectJAutoProxyCreator。到這裏我們就可以知道Aop的功能完成肯定是在 AnnotationAwareAspectJAutoProxyCreator 中完成的,因此下面我們開始分析 AnnotationAwareAspectJAutoProxyCreator 的代碼。


注:

  1. 這裏之所以 beanName (AUTO_PROXY_CREATOR_BEAN_NAME) 和 bean的類型並不相同,是因爲這個beanName 特指內部的自動代理創建器,但是自動創建代理器會對應多種不同的實現方式。比如在默認的事務中,注入的bean類型卻爲InfrastructureAdvisorAutoProxyCreator,而AOP的實現卻是 AnnotationAwareAspectJAutoProxyCreator

  2. 關於優先級的問題,我們可以看到APC_PRIORITY_LIST 集合的順序,下標越大,優先級越高。因此可以得知優先級的順序應該是
    InfrastructureAdvisorAutoProxyCreator < AspectJAwareAdvisorAutoProxyCreator < AnnotationAwareAspectJAutoProxyCreator


三、AnnotationAwareAspectJAutoProxyCreator

上面我們可以看到,整個過程就是將 AnnotationAwareAspectJAutoProxyCreator 註冊到 Spring 中並且設置一些屬性。

那麼我們來看看 AnnotationAwareAspectJAutoProxyCreator ,其主要邏輯實際上還是在其父類 AbstractAutoProxyCreator 中完成。(包括事務的實現邏輯也主要在 AbstractAutoProxyCreator 中,這一點後續關於事務的源碼分析會詳細解讀)

在這裏插入圖片描述
AnnotationAwareAspectJAutoProxyCreator 實現了 SmartInstantiationAwareBeanPostProcessor接口的方法,SmartInstantiationAwareBeanPostProcessor 接口方法穿插在 Bean初始化的過程中,轉念一想,Spring Aop的核心思想就是動態代理,那麼必然會在bean初始化的時候"做手腳"。因此我們下面的重心就放在 SmartInstantiationAwareBeanPostProcessor 的方法分析上。


注:關於 後處理器SmartInstantiationAwareBeanPostProcessor 的內容 具體請參考 Spring源碼分析衍生篇四:後處理器 BeanPostProcessor


上面也說了,其主要邏輯在AbstractAutoProxyCreator 中實現,這裏是在AbstractAutoProxyCreator 中實現的 SmartInstantiationAwareBeanPostProcessor 方法,所以我們下面看的實際是 AbstractAutoProxyCreator 類,


四、AbstractAutoProxyCreator

這裏額外提一下,Spring事務的實現也依賴於 AbstractAutoProxyCreator 類,並且邏輯與Aop 的實現基本一致,因爲事務的實現的方式也是Aop代理。後面新篇講到事務時會相信解讀。


下面是AbstractAutoProxyCreatorSmartInstantiationAwareBeanPostProcessor 的一些實現方法的實現

	@Override
	@Nullable
	public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
		// 從代理換緩存中獲取代理類型
		if (this.proxyTypes.isEmpty()) {
			return null;
		}
		Object cacheKey = getCacheKey(beanClass, beanName);
		return this.proxyTypes.get(cacheKey);
	}

	@Override
	@Nullable
	public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
		return null;
	}

	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

	@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;
			}
			// 是基礎設施類 || 是被 @AspectJ 註解修飾的類。則跳過 Aop代理
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// 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);
			// 創建代理類
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) {
		return true;
	}

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		return pvs;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return 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;
	}

我們可以根據 SmartInstantiationAwareBeanPostProcessor 方法的調用順序進行分析。如果想要生成代理,可以在bean初始化之後。也就是 postProcessBeforeInstantiation 方法中。在 postProcessBeforeInstantiation 方法中我們可以看到關鍵方法是在於 wrapIfNecessary。不過在此之前我們先來看看 postProcessBeforeInstantiation方法中的一段分析

1. 是否跳過代理

我們這一部分主要是用來分析AbstractAutoProxyCreator#postProcessBeforeInstantiation 中的這一段代碼:

	// 是基礎設施類 || 是被 @AspectJ 註解修飾的類。則跳過 Aop代理
	if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return null;
	}

這段代碼將在bean加載前判斷bean是否交由Aop代理,亦或者換一種說法 : 判斷將該Bean交由Spring容器創建還是交由Aop 創建。在實際創建bean代理時候,Spring會根據cacheKey 獲取到值,爲false則不需要代理。

我們可以看到關鍵的判斷條件就是下面兩個:

1.1. isInfrastructureClass(beanClass)

這裏我們可以很清楚的看到,如果當前bean是基礎類(AdvicePointcutAdvisorAopInfrastructureBean及其子類),則返回true。

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

1.2. shouldSkip(beanClass, beanName)

	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
		// 尋找所有候選代理增強點。關於這個方法,在後面關於 getAdvicesAndAdvisorsForBean 的文章中會詳細分析,這裏就不分析
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			// 從前面的代碼分析可以看出,如果是Aop 的動態封裝都是基於 InstantiationModelAwarePointcutAdvisorImpl 也就是 InstantiationModelAwarePointcutAdvisor,自然是繼承PointcutAdvisor
			// 如果 代理類基於 AspectJPointcutAdvisor  && aspectName==beanName,即當前初始化的類是ApspectJ類本身。則返回true,跳過代理
			if (advisor instanceof AspectJPointcutAdvisor &&
					((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
				return true;
			}
		}
		// 父類shouldSkip 判斷了文件是否是 .ORIGINAL 後綴,是則跳過。
		return super.shouldSkip(beanClass, beanName);
	}

關於if語句判斷條件:

  1. advisor instanceof AspectJPointcutAdvisor
    基礎篇有講過。Advisor兩個子接口PointcutAdvisorIntroductionAdvisor 。IntroductionAdvisor與PointcutAdvisor 最本質上的區別就是,IntroductionAdvisor只能應用於類級別的攔截,只能使用Introduction型的Advice。而不能像PointcutAdvisor那樣,可以使用任何類型的Pointcut,以及幾乎任何類型的Advice。

    而通過 Spring Aop 動態注入的是 Advisor 默認都是 InstantiationModelAwarePointcutAdvisorImpl 都滿此條件。所以這裏爲false 的情況只有硬編碼注入時IntroductionAdvisor 類型的 Advisor ,所以這裏基本都會返回true。

  2. ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) : 這裏就是判斷beanName 是否是 @AspectJ 註解修飾的bean的name。

    那麼就可以看出,這裏返回ture的條件是 @ApsectJ 修飾的 AspectJPointcutAdvisor 類。即 被 @ApsectJ 修飾的類會跳過代理


綜上,跳過Aop代理的條件就是:Aop基礎設施類或者 被@AspectJ修飾的類


2. AbstractAutoProxyCreator#wrapIfNecessary

postProcessAfterInitialization 方法中我們可看到關鍵方法 wrapIfNecessary。
wrapIfNecessary 主要是用來判斷當前bean是否需要代理,如果需要,則進行bean封裝。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 如果已經處理過
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 無需增強。這個在postProcessBeforeInstantiation 方法中對 cacheKey 進行了判斷緩存,this.advisedBeans.get(cacheKey) 的返回值代表當前bean是否需要aop代理。
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 給定的bean類是否是一個基礎設施類(Advice、Pointcut、Advisor、AopInfrastructureBean) || 配置了指定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;
	}

可以很明顯的發現下面兩個方法是關鍵。

// 獲取適配的增強點
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 根據增強點創建對象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);

2.1. 獲取代理增強點 - getAdvicesAndAdvisorsForBean

篇幅所限,新開文章:Spring源碼分析十二:@AspectJ方式的AOP 之 getAdvicesAndAdvisorsForBean

2.2. 創建代理類 - createProxy

	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);
		// 判斷當前bean 是使用 TargetClass 代理還是接口代理
		if (!proxyFactory.isProxyTargetClass()) {
			// 檢查 proxyTargeClass設置以及preservetargetClass 屬性
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		// 將攔截器 Interceptors 封裝成增強器 Advisor
		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());
	}

代碼中已經有詳細的註釋了,可以看到代理類的創建Spring委託給 ProxyFactory 去處理,而在此函數中主要是對 ProxyFactory 的初始化操作:

  1. 獲取當前類的屬性
  2. 添加代理接口
  3. 封裝Advisor 並加入到ProxyFactory 中
  4. 設置要代理的類
  5. 通過customizeProxyFactory定製代理類 ,對ProxyFactory 進一步封裝
  6. 進行獲取代理操作

我們下面主要下面兩個方法:

2.2.1. buildAdvisors(beanName, specificInterceptors);

需要注意的是:這裏的參數 就是 Object[] specificInterceptors 就是 getAdvicesAndAdvisorsForBean 方法返回的 Advisor,通過對 getAdvicesAndAdvisorsForBean 方法的分析我們可以得知, specificInterceptors 應該全是 InstantiationModelAwarePointcutAdvisorImpl 類型。

	protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
		// Handle prototypes correctly...
		// 解析註冊的所有 Interceptor Name。即我們可以手動添加一些 攔截器,這裏將手動添加的攔截器保存到commonInterceptors  中
		Advisor[] commonInterceptors = resolveInterceptorNames();

		List<Object> allInterceptors = new ArrayList<>();
		if (specificInterceptors != null) {
			// 加入攔截器
			allInterceptors.addAll(Arrays.asList(specificInterceptors));
			if (commonInterceptors.length > 0) {
				if (this.applyCommonInterceptorsFirst) {
					allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
				}
				else {
					allInterceptors.addAll(Arrays.asList(commonInterceptors));
				}
			}
		}
		if (logger.isTraceEnabled()) {
			int nrOfCommonInterceptors = commonInterceptors.length;
			int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
			logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
					" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
		}

		Advisor[] advisors = new Advisor[allInterceptors.size()];
		for (int i = 0; i < allInterceptors.size(); i++) {
			// 攔截器進行轉化爲 Advisor
			advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
		}
		return advisors;
	}

...
	//  this.interceptorNames 是自己通過set設置的屬性。在基礎篇中Advice 有過類似的設置。我們這裏是沒有的
	private Advisor[] resolveInterceptorNames() {
		BeanFactory bf = this.beanFactory;
		ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
		List<Advisor> advisors = new ArrayList<>();
		// 將 interceptorNames 獲取到的攔截器保存起來,並返回。
		for (String beanName : this.interceptorNames) {
			if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
				Assert.state(bf != null, "BeanFactory required for resolving interceptor names");
				Object next = bf.getBean(beanName);
				advisors.add(this.advisorAdapterRegistry.wrap(next));
			}
		}
		return advisors.toArray(new Advisor[0]);
	}


我們下面來看一下 this.advisorAdapterRegistry.wrap(allInterceptors.get(i)); 的實現

	public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
		// 如果 adviceObject  本身就是 Advisor則不需進一步操作
		if (adviceObject instanceof Advisor) {
			return (Advisor) adviceObject;
		}
		// 此封裝方法只能處理Advisor 和 Advice兩種類型,如果不是將不能封裝
		if (!(adviceObject instanceof Advice)) {
			throw new UnknownAdviceTypeException(adviceObject);
		}
		Advice advice = (Advice) adviceObject;
		if (advice instanceof MethodInterceptor) {
			// So well-known it doesn't even need an adapter.
			// 如果是MethodInterceptor 類型則使用 DefaultPointcutAdvisor 封裝
			return new DefaultPointcutAdvisor(advice);
		}
		// 如果存在 Advisor 的適配器則同樣需要進行封裝。
		for (AdvisorAdapter adapter : this.adapters) {
			// Check that it is supported.
			if (adapter.supportsAdvice(advice)) {
				return new DefaultPointcutAdvisor(advice);
			}
		}
		throw new UnknownAdviceTypeException(advice);
	}

DefaultAdvisorAdapterRegistry#wrap 方法也很簡單,就是將 adviceObject 包裝成 Advisor 。

2.2.2. proxyFactory.getProxy(getProxyClassLoader());

上述代碼中 proxyFactory.getProxy(getProxyClassLoader()); 會繼續調用到 DefaultAopProxyFactory#createAopProxy
因此我們來看 DefaultAopProxyFactory#createAopProxy

首先我們來看一下 proxyFactory.getProxy 方法。

	public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}

顯然意見我們需要將這個內容分爲兩步: createAopProxy() 和 getProxy(classLoader)

2.2.2.1 createAopProxy()

ProxyCreatorSupport#createAopProxy 會調用 DefaultAopProxyFactory#createAopProxy。因此,這裏我們來看 DefaultAopProxyFactory#createAopProxy 的實現

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (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)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

在這個方法中我們可以看到 Aop代理使用了 JDK動態代理和 Cglib動態代理兩種動態代理模式,並根據某些參數來進行選擇代理方式


createAopProxy 代碼中我們可以看到幾個參數:

  • optimize : 用來控制通過CGlib 創建的代理是否使用激進的優化策略,一般默認false,對JDK動態代理無效。
  • proxyTargetClass:若爲true,則目標類本身被代理,而不是代理目標類的接口,創建 cglib代理。
  • hasNoUserSuppliedProxyInterfaces:是否存在代理接口

即:

  • 如果目標對象實現了接口,默認會採用JDK動態代理實現AOP
  • 如果目標對象實現了接口,可以強制使用CGLIB動態代理實現AOP
  • 如果目標對象沒有實現接口,必須採用CGLIB代理,Spring會自動在JDK動態代理和CGLIB代理之前切換。

2.2.2.2 getProxy(classLoader)

首先我們需要知道的是,調用這個方法的是 createAopProxy() 方法的返回值,那麼就可能是JdkDynamicAopProxy.getProxy 或者 ObjenesisCglibAopProxy.getProxy。這裏就不再具體分析其代理類生成過程了,就是和Cglib代理和Jdk代理的基本流程。

五、總結

總結一下整體邏輯和思想,寫的並不嚴謹。

  1. 服務啓動時,通過 @EnableAspectJAutoProxy 開始aop功能,引入 AnnotationAwareAspectJAutoProxyCreator 自動創建配置器
  2. AnnotationAwareAspectJAutoProxyCreator 中。會在bean創建過程中判斷bean是否需要被切入,判斷的方式是是否有滿足的 Advisor,這其中有一部分是編碼直接注入的(比如事務的 BeanFactoryTransactionAttributeSourceAdvisor),但是在Spring Aop 中,由於匹配規則的衆多,需要動態生成 Advisor
  3. 如果需要切入,則創建bean 的代理。代理的方式有jdk代理和cglib代理,根據情況選擇代理方式。
  4. 如果不需要切入,則什麼也不做。

至此,@AspectJ方式的AOP 的源碼分析結束。


以上:內容部分參考
《Spring實戰》
《Spring源碼深度解析》
https://www.cnblogs.com/cheng21553516/p/12190008.html
https://blog.csdn.net/wyl6019/article/details/80136000
如有侵擾,聯繫刪除。 內容僅用於自我記錄學習使用。如有錯誤,歡迎指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章