Spring AOP源碼解析(一)Advisor獲取

一、入口

AOP的Jar包如下如所示:

META-INF中是Spring自定義標籤的配置文件,對<aop>標籤的支持

spring.schemas配置如下,作用是定義<aop>標籤的內容(根據不同版本,Spring使用不同的xsd文件來描述):

http\://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-2.5.xsd=org/springframework/aop/config/spring-aop-2.5.xsd
http\://www.springframework.org/schema/aop/spring-aop-3.0.xsd=org/springframework/aop/config/spring-aop-3.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-3.1.xsd=org/springframework/aop/config/spring-aop-3.1.xsd
http\://www.springframework.org/schema/aop/spring-aop-3.2.xsd=org/springframework/aop/config/spring-aop-3.2.xsd
http\://www.springframework.org/schema/aop/spring-aop-4.0.xsd=org/springframework/aop/config/spring-aop-4.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-4.1.xsd=org/springframework/aop/config/spring-aop-4.1.xsd
http\://www.springframework.org/schema/aop/spring-aop-4.2.xsd=org/springframework/aop/config/spring-aop-4.2.xsd
http\://www.springframework.org/schema/aop/spring-aop-4.3.xsd=org/springframework/aop/config/spring-aop-4.3.xsd
http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.3.xsd

spring.handles中配置只有一行,如下所示:

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

配置的入口便是AopNamespaceHandler。它的定義如下:

public class AopNamespaceHandler extends NamespaceHandlerSupport {

	/**
	 * 註冊幾個BeanDefinitionParser,用來支持config、spring-configured、aspectj-autoproxy、scoped-proxy標籤的功能
	 */
	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}

}

二、AspectJAutoProxyBeanDefinitionParser註冊AOP組件

在平時使用Spring AOP基於註解配置AOP的時候,配置文件中都需要加入下面這行配置來開啓AOP:

	<!--開啓字段AOP代理-->
	<aop:aspectj-autoproxy/>

對應到前面的代碼中,Spring就會使用AspectJAutoProxyBeanDefinitionParser來解析這行配置:

	public BeanDefinition parse(Element element, ParserContext parserContext) {
		//註冊AspectJAnnotationAutoProxyCreator(具體實現類是AnnotationAwareAspectJAutoProxyCreator)
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		//對於註解中子類的處理
		extendBeanDefinition(element, parserContext);
		return null;
	}

代碼中重點是registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,該方法會註冊AnnotationAwareAspectJAutoProxyCreator:

	public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {
		//註冊beanName爲"org.springframework.aop.config.internalAutoProxyCreator"的bean,如果bean爲null的話
		//bean的類型爲AspectJAwareAdvisorAutoProxyCreator
		BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
		//對於proxy-target-class以及expose-proxy屬性的處理
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		//註冊組件並通知,便於監聽器進一步處理
		registerComponentIfNecessary(beanDefinition, parserContext);
	}

a、註冊AspectJAwareAdvisorAutoProxyCreator

AopConfigUtil.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法實現中,會直接將AspectJAwareAdvisorAutoProxyCreator註冊到BeanFactory中:

	public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
		return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
	}

下面是註冊(或升級)的源碼實現:

	private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		//如果已經存在beanName爲"org.springframework.aop.config.internalAutoProxyCreator"的bean並且與當前傳入的類型不同,
		//則比較兩個bean的優先級,保留優先級高的那個
		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) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
		//註冊AspectJAwareAdvisorAutoProxyCreator到BeanFactory
		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;
	}
  1. 如果存在"org.springframework.aop.config.internalAutoProxyCreator"的bean並且與當前傳入的類型不同,保留優先級更高的bean
  2. 如果不存在,註冊當前bean的信息到BeanFactory

b、處理proxy-target-class以及expose-proxy屬性

註冊了AspectJAwareAdvisorAutoProxyCreator後,Spring會接着解析<aop:aspectj-autoproxy>標籤中的proxy-target-class和expose-proxy屬性,如果屬性存在的話,會將屬性值設置到AspectJAwareAdvisorAutoProxyCreator對應的BeanDefinition中:

	private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
		if (sourceElement != null) {
			//proxy-target-class屬性的處理
			boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
			if (proxyTargetClass) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			//expose-proxy屬性的處理
			boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
			if (exposeProxy) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

下面是設置屬性值的代碼:

	public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			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);
			definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
		}
	}
  • proxy-target-class:強制使用CGLib爲目標對象創建代理(如果沒有設置該屬性的話,如果目標對象實現了至少一個接口,則會使用JDK的動態代理)。但是,CGLib的有兩個問題需要考慮:1.無法代理final class,因爲CGLib是通過生成子類來創建代理對象的;2.需要無參構造函數
  • expose-proxy:爲了解決目標對象內部的自我調用時,無法實現切面的增強的問題

三、創建AOP代理

1、攔截bean創建

在上一步中,BeanFactory中已經註冊了一個特殊的bean,bean的類型爲 AspectJAwareAdvisorAutoProxyCreator ,該類的繼承結構爲:

AspectJAwareAdvisorAutoProxyCreator實現了BeanPostProcessor接口,所以也就有機會在bean創建過程中爲bean創建代理,接口實現如下:

初始化前調用處理器

	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}

postProcessBeforeInitialization方法只是將bean原樣返回,並沒有做任何處理,因此可以看出,AOP代理的bean都是已經初始化好的bean。

初始化後調用處理器:

	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			//緩存鍵:1.beanName不爲空的話,使用beanName(FactoryBean會在見面加上"&")
			//2.如果beanName爲空,使用Class對象作爲緩存的key
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				//如果條件符合,則爲bean生成代理對象
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

wrapIfNecessary

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		//如果已經處理過(targetSourcedBeans存放已經增強過的bean)
		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		//advisedBeans的key爲cacheKey,value爲boolean類型,表示是否進行過代理
		//已經處理過的bean,不需要再次進行處理,節省時間
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		//是否是內部基礎設置類Class || 配置了指定bean不需要代理
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// 獲取所有適用的Advisor.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		//如果獲取的增強不爲null,則爲該bean創建代理(DO_NOT_PROXY=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;
		}
		//標記該cacheKey已經被處理過
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

代碼流程:

  1. 如果已經處理過,且該bean沒有被代理過,則直接返回該bean
  2. 如果該bean是內部基礎設置類Class 或 配置了該bean不需要代理,則直接返回bean(返回前標記該bean已被處理過)
  3. 獲取所有適合該bean的增強Advisor
  4. 如果增強不爲null,則爲該bean創建代理對象,並返回結果
  5. 標記該bean已經被處理過

對於需要代理的bean來說,總體有兩個步驟:

  1. 獲取增強方法或增強器
  2. 根據獲取結果進行代理

2、是否需要代理

判斷一個bean是否需要代理會經過3次判斷:

  1. 是否是一個內部基礎設置類
  2. 是否配置了bean跳過代理
  3. 是否存在合適的增強器

a、是否是一個內部設施類

判斷一個bean是否是一個內部基礎設置類,由方法isInfrastructureClass提供:

	//AnnotationAwareAspectJAutoProxyCreator.class
	protected boolean isInfrastructureClass(Class<?> beanClass) {
		// 父類判斷是否是內部設置 || 是否是一個Aspect切面
		return (super.isInfrastructureClass(beanClass) || this.aspectJAdvisorFactory.isAspect(beanClass));
	}

判斷是否是內部設置類交由父類(AspectJAwareAdvisorAutoProxyCreator)判斷,/AnnotationAwareAspectJAutoProxyCreator還增加了一條限制就是Aspect類也無法被增強

AspectJAwareAdvisorAutoProxyCreator實現:

	protected boolean isInfrastructureClass(Class<?> beanClass) {
		//如果bean繼承自Advice、Pointcut、Advisor、AopInfrastructureBean
		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無法被增強

isAspect方法實現:

	public boolean isAspect(Class<?> clazz) {
		//如果bean帶有@Aspect註解,或被Ajc(AspectJ編譯器)編譯
		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
	}

綜上,如果一個bean繼承自Advice、Pointcut、Advisor、AopInfrastructureBean 或者 帶有@Aspect註解,或被Ajc(AspectJ編譯器)編譯都會被認定爲內部基礎設置類

b、是否指定bean不被代理

實現方法shouldSkip,實現如下:

	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) {
			//如果當前beanName與某一個切面名相同則跳過
			if (advisor instanceof AspectJPointcutAdvisor) {
				if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
					return true;
				}
			}
		}
            //默認返回false
		return super.shouldSkip(beanClass, beanName);
	}

shouldSkip會跳過beanName與某一個切面名相同的bean

c、是否存在合適的增強器

如下代碼:

		//1.獲取合適的增強器
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		//2.如果增強器不爲空,則創建代理
		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;
		}

Spring會先查找出所有合適的增強器,如果增強器不爲空(null),則表示當前bean需要代理

3、獲取增強器Advisor

獲取增強器的實在位於getAdvicesAndAdvisorsForBean:

	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
		//獲取合適的增強器
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		//數組爲空,返回null
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
	
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		//獲取所有的增強器
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		//增強器中匹配bean
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		//模版方法,由子類拓展增強器
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

獲取指定bean的增強方法分爲兩個步驟:

  1. 獲取所有的增強--findCandidateAdvisors
  2. 尋找所有增強中使用於bean的增強--findAdvisorsThatCanApply
  3. 通過模版方法,交由子類拓展增強器

a、獲取所有的增強 findCandidateAdvisors

AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors:

	protected List<Advisor> findCandidateAdvisors() {
		//調用父類方法加載XML配置文件中聲明的AOP增強
		List<Advisor> advisors = super.findCandidateAdvisors();
		//獲取所有通過註解添加的AOP增強
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		return advisors;
	}

增強器分類兩類處理:一種是通過<aop>標籤添加的增強,這部分會在解析配置文件的時候添加到Spring容器中,主需要獲取當前容器中Advisor類型的bean就可以獲取到該類增強;另一中是通過註解添加的增強,獲取此類增強還需要對bean進行遍歷解析,下面是解析過程。

BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors:

	public List<Advisor> buildAspectJAdvisors() {
		//因爲解析會很消耗性能,所以Spring會使用aspectBeanNames保存解析結果
		List<String> aspectNames = this.aspectBeanNames;

		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				//雙重非空判斷,避免再次解析
				if (aspectNames == null) {
					List<Advisor> advisors = new LinkedList<Advisor>();
					aspectNames = new LinkedList<String>();
					//獲取BeanFactory中Object類型的bean(所有bean)的beanName列表
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					for (String beanName : beanNames) {
						//排除不合法的ban,由子類定義規則,默認返回true
						if (!isEligibleBean(beanName)) {
							continue;
						}
						//獲取bean對應類型
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
						//如果存在@Aspect註解
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							//保存bean類型以及@Aspect註解信息
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							//檢查@Aspect註解的value值,驗證生成的增強是否是單例
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
								//獲取標記Aspect註解的增強方法
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								//如果bean是單例,則緩存bean的增強器
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								//bean非單例,只能緩存bean對應的增強器創建工廠
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
							}
							else {
								// 切面創建模式非單例
								//如果切面是非單例,但是bean是單例,拋出異常
								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 LinkedList<Advisor>();
		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;
	}

上面代碼流程:

  1. 獲取所有beanName
  2. 遍歷所有的beanName,篩選出帶有@Aspect註解的bean
  3. 創建增強
  4. 解析結果添加到緩存

創建增強器getAdvisors:

對應我們通過@Aspect註解加入的增強來說,最重要的就是將@Before等註解標記的方法轉化爲一個增強器,也就是getAdvisors方法的功能,實現位置爲ReflectiveAspectJAdvisorFactory->getAdvisors:

	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		//目標Class
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		//代理對象的beanName
		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
		//對Class上@Aspect註解信息的驗證
		validate(aspectClass);

		//應用裝飾器模式。將aspectInstanceFactory實例化的增強器緩存起來,避免多次創建
		MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
				new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

		List<Advisor> advisors = new LinkedList<Advisor>();
		//getAdvisorMethods方法會篩選出不帶有@Pointcut註解的方法
		for (Method method : getAdvisorMethods(aspectClass)) {
			//創建增強器對象
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		//通過在頭部加入SyntheticInstantiationAdvisor增強器,達到延遲初始化切面bean的目的
		if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
			advisors.add(0, instantiationAdvisor);
		}

		//對@DeclareParent註解功能的支持
		for (Field field : aspectClass.getDeclaredFields()) {
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		return advisors;
	}

方法會遍歷Class中所有不帶有@Pointcut註解的Method對象,並通過該Method對象創建Advisor增強器,getAdvisors:

	public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
			int declarationOrderInAspect, String aspectName) {
		//驗證目標bean的Class對象
		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
		
		//獲取方法上的註解信息,並將配置的表達式封裝爲AspectJExpressionPointcut
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}
		
		//將Pointcut對象以及Method對象封裝到InstantiationModelAwarePointcutAdvisorImpl類中
		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}

終於到了Spring對Method封裝的地方,Spring先獲取方法上的AOP註解(如@Before等),並將註解信息封裝到AspectJExpressionPointcut對象中,最後再將Method對象和AspectJExpressionPointcut對象封裝到InstantiationModelAwarePointcutAdvisorImpl類中,組合成爲一個增強器。

AspectJExpressionPointcut對象會解析註解中的表達式,並以此匹配類型和方法以絕對是否進行攔截,並調用增強方法、

 

b、獲取匹配的增強器

findAdvisorsThatCanApply:

	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
		//通過一個ThreadLocal變量,設置當前代理的beanName
		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			//過濾advisors
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

這一步驟主要是環境變量的設置,真正過濾的操作放在了AopUtils.findAdvisorsThatCanApply中:
 

	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
		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) {
				// 引介增強已經處理過了
				continue;
			}
			//對於普通增強器的處理
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

從上面代碼中,可以看到,對增強器進行過濾的函數就是canApply方法:

	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		if (advisor instanceof IntroductionAdvisor) {
			//引介增強是通過設置ClassFilter進行匹配
			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;
		}
	}

首先獲取Pointcut對象,繼續調用重載的canApply方法:

	public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		//1.ClassFilter匹配
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}
		
		//MethodMatcher的匹配
		
		//如果切點的MethodMatcher類型爲MethodMatcher.TRUE,則表示對所有方法都進行匹配
		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}
		
		//遍歷接口中所有定義的方法,通過MethodMatcher進行匹配
		Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		classes.add(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;
	}

最後是通過ClassFilter已經MethodMatcher匹配目標類包括其實現的接口中定義的方法

c、子類拓展

在獲取增強器的過程中,方法findEligibleAdvisors中調用了一個名爲extendAdvisors的方法,用作子類對已經查找完成的增強器進行拓展,子類AspectJAwareAdvisorAutoProxyCreator進行了實現:

	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
		AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
	}

該方法會添加一個包含ExposeInvocationInterceptor的增強器到增強器列表頭部。該攔截器將會是第一個被應用的,調用它時會將MethodInvocation放置到ThreadLocal結構中,供其他@Aspect註解對應的增強器使用。它的作用其實就是爲了讓通過@Aspect註解加入的增強器可以訪問到MethodInvocation對象

 

 

 

 

 

 

 

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