Spring源碼之創建AOP代理之增強器的獲取
- 2021 年 10 月 7 日
- 筆記
- spring5源碼解析
前言
在上一篇博文中我們說到了通過自定義配置完成了對AnnotationAwareAspectJAutoProxyCreator
類型的自動註冊,那麼這個類究竟做了什麼工作從而完成AOP的操作呢?首先我們看一下AnnotationAwareAspectJAutoProxyCreator
的類圖結構,如圖:
AOP的源碼解析操作入口
從UML類圖中我們看到`AnnotationAwareAspectJAutoProxyCreator`這個類實現了`BeanPostProcessor`接口,而實現這個`BeanPostProcessor`後,當Spring加載這個Bean時會在實例化之前調用器`postProcessorAfterIntialization`方法,而我們就從這裡進行分析AOP的邏輯
-
首先我們先看一下它父類
AbstractAutoProxyCreator
的postProcessorIntialization
方法 -
看源碼(具體實現在
AbstractAutoProxyCreator.class
)
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 根據bean的class 和 name構建出一個key 格式:beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果它適合被代理,則需要指定封裝bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
在上面代碼中用到了方法wrapIfNecessary
,進入到該函數方法的內部:
- 看源碼(具體實現在
AbstractAutoProxyCreator.class
)
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;
}
// 給定的bean類是否是一個基礎設施類,基礎設施類不應該被代理,或者配置了指定的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;
}
從上面的函數中我們可以大概看出代理的創建過程的一個雛形。當然真正的開始之前還需要一些個判斷,比如是否已經處理過或者是 是否需要跳過的bean,而真正創建代理的代碼是在`getAdvicesAndAdvisorsForBean`函數開始的。
** 創建代理需要兩個步驟:**
- 獲取增強方法或增強器;
- 根據獲取的增強來進行代理。
上述兩個步驟其中邏輯是十分複雜的,首先來看看獲取增強方法的邏輯實現。獲取增強的方法getAdvicesAndAdvisorsForBean
是在AbstractAdvisorAuroProxyCreator
中實現的,代碼如下:
- 看源碼(具體實現在
AbstractAdvisorAuroProxyCreator.class
)
@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();
}
- 源碼分析
主要查看上述函數體內的findEligibleAdvisor
方法。進入該方法實現也在AbstractAdvisorAuroProxyCreator.class
中
- 看源碼(具體實現在
AbstractAdvisorAutoProxyCreator.class
)
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;
}
- 源碼分析
通過findEligbleAdvisor
的具體實現我們看到,對於指定bean的增強方法的獲取包含了兩個步驟:
- 獲取所有增強,
- 尋找所有增強中 對於bean的增強並應用(也就是尋找匹配bean的增強器)。
函數中的findCandidateAdvisors
和findAdvisorsThatCanApply
便是做了這兩件事
當然如果這個方法沒有找到增強器,getAdvicesAndAdvisorsForBean
就會返回一個DO_NOT_PROXY
,DO_NOT_PROXY時已經定義好的null
獲取增強器
從一開始我們分析的就是基於註解進行的AOP,所以對於findidateAdvisors
的實現是由AnnotationAwareAspectJAutoProxyCreator
類的findCandidateAdvisors
方法完成的。
- 看源碼(具體實現在
AnnotationAwareAspectJAutoProxyCreator.class
)
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 當使用註解方式配置AOP的時候並不是對xml配置文件的支持進行了丟棄
// 在這裡調用父類加載配置文件中的AOP聲明
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
- 源碼解析:
首先我們先看一下AnnotationAwareAspectJAutoProxyCreator.class
這個類的UML,
在上圖中我們看到AnnotationAwareAspectJAutoProxyCreator間接繼承了AbstractAdvisorsAutoProxyCreator,在實現獲取增強方法中保留了父類的獲取配置文件中定義的增強,是由List<Advisor> advisors = super.findCandidateAdvisors();
實現;
此外同時還添加了獲取Bean的註解增強的功能,是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
這個方法實現的
Spring獲取增強器(增強方法)的解析思路大致如下:
- 獲取所有的beanName,這一步驟中所有的beanFactory中註冊的Bean都會被提取出來。
- 遍歷所有的beanName,並找出使用**@Aspect註解聲明的類,並進行進一步處理。
- 對於標記Aspect註解的類進行增強器的提取。
- 將提取結果加入緩存
接下來我們分析一下以上步驟的實現,首先
- 看this.aspectJAdvisorsBuilder.buildAspectJAdvisors()源碼的實現(具體實現在
BeanFactoryAspectJAdvisorsBuilder.class
)
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 獲取所有的beanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 循環所有的beanName獲取 獲取聲明AspectJ的類,找出對應的增強方法
for (String beanName : beanNames) {
// 不合法的bean 則略過,由子類定義規則返回true
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
// 獲取對應的bean Class類型
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 解析標記AspectJ註解的增強方法
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 將增強器加入緩存 下次可以直接取
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 記錄在緩存中
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
執行到此,Spring就完成了Advisor的提取,在上面的步驟中**最繁雜最重要**的就是增強**器的獲取**,而這一步又交給了`getAdvisors`方法去實現的。(`this.advisorFactory.getAdvisors(factory);`)
- 首先看this.advisorFactory.isAspect(beanType)源碼(具體實現在
AbstractAspectJAdvisorFactory.class
)
@Override
public boolean isAspect(Class<?> clazz) {
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
緊接着再查看一下findAnnotation
方法:
@Nullable
public static <A extends Annotation> A findAnnotation(Class<?> clazz, @Nullable Class<A> annotationType) {
if (annotationType == null) {
return null;
}
// Shortcut: directly present on the element, with no merging needed?
if (AnnotationFilter.PLAIN.matches(annotationType) ||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
// 判斷此Class 是否存在Aspect.class註解
A annotation = clazz.getDeclaredAnnotation(annotationType);
if (annotation != null) {
return annotation;
}
// For backwards compatibility, perform a superclass search with plain annotations
// even if not marked as @Inherited: e.g. a findAnnotation search for @Deprecated
Class<?> superclass = clazz.getSuperclass();
if (superclass == null || superclass == Object.class) {
return null;
}
return findAnnotation(superclass, annotationType);
}
// Exhaustive retrieval of merged annotations...
return MergedAnnotations.from(clazz, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
.get(annotationType).withNonMergedAttributes()
.synthesize(MergedAnnotation::isPresent).orElse(null);
}
這裡如果bean存在Aspect.class註解,那麼就可以獲取此bean的增強器了,接下來我們回到BeanFactoryAspectJAdvisorsBuilder類中查看this.advisorFactory.getAdvisors(factory);方法。
- 看源碼(具體實現在
ReflectiveAspectJAdvisorFactory.class
)
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 獲取標記AspectJ的類
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 獲取標記AspectJ的name
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 對於aspect class的每一個帶有註解的方法進行循環(除了@Pointcut註解的方法除外),取得Advisor,並添加到集合里
// 這裡應該取到的是Advice,然後取得我們自定義的切面類中的PointCut,組合成Advisor
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 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;
}
普通增強器的獲取
普通增強其的獲取邏輯通過getAdvisor
方法實現,實現步驟包括對切點的註解的獲取以及根據註解信息生成增強。
首先我們看一下 getAdvisorMethods(aspectClass)這個方法,它很巧妙的使用接口定義一個匿名回調,把帶有註解的Method都取出來,放到集合里。
- 看源碼
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
if (methods.size() > 1) {
methods.sort(adviceMethodComparator);
}
return methods;
}
然後在看一下函數體內的doWithMethods
方法 具體實現在ReflectionUtils中
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
Method[] methods = getDeclaredMethods(clazz, false);
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
doWithMethods(clazz.getSuperclass(), mc, mf);
}
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
然後我們在回到ReflectiveAspectJAdvisorFactory.class類中獲取普通增強器的getAdvisor方法
- 看源碼(具體實現在
ReflectiveAspectJAdvisorFactory.class
)
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 獲取Pointcut信息 主要是獲取Pointcut表達式
// 把Method對象也傳進去的目的是,比較Method對象上的註解,是不是下面的註解的其中的一個,
// 如果不是返回null;如果是就把Pointcut內容包裝返回
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 根據Pointcut信息生成增強器
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
切點信息的獲取
所謂獲取切點信息就是指註解的表達式信息的獲取,如@Before(“test()”)。
- 看源碼(具體在
ReflectiveAspectJAdvisorFactory.class
)
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 獲取方法上的註解,比較Method對象上的註解是不是下面其中的一個,如果不是返回null
// 被比較的註解:Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 使用AspectJExpressionPointcut實例封裝獲取的信息
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 提取到註解中的表達式並設置進去
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
我們再看一下上面使用到的findAspectJAnnotationOnMethod
方法的實現
- 看源碼(具體是現在
AbstractAspectJAdvisorFactory.class
)
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
小插曲:注意一下上面的ASPECTJ_ANNOTATION_CLASSES
變量,它設置了查找的註解類:
- 源碼
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
再次回到findAspectJAnnotationOnMethod方法的實現,裏面使用了findAnnotation
方法,跟蹤該方法
- 看源碼(具體實現在
AbstractAspectAdvisorFacrory.class
)
/**
* 獲取指定方法上的註解 並使用AspectAnnotation進行封裝
* @param method
* @param toLookFor
* @param <A>
* @return
*/
@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
return new AspectJAnnotation<>(result);
}
else {
return null;
}
}
此方法的功能是獲取指定方法上的註解並使用AspectJAnnotation封裝。
根據切點信息獲取增強類
所有的增強都由Advisor實現類InstantiationModelAwarePointCutAdvisorImpl進行統一封裝。我們簡單看一下其構造函數:
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 初始化Advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
通過對上面的構造函數的分析,發現封裝過程只是簡單的將信息封裝在類的實例中,所有的信息都是單純的複製。在實例初始化的工程中還完成了對於增強器的初始化。因為不同的增強所體現的邏輯是不同的,比如`@Before("test()")`和`@After("test()")`標籤的不同就是增強器的位置不同,所以需要不同的增強器來完成不同的邏輯,而根據註解中的信息初始化對應的增強器就是在`instantiateAdvice`函數中實現的,繼續跟蹤源碼:
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
接下來再繼續跟蹤getAdvice函數的具體實現
- 看源碼(具體實現在
ReflectiveAspectJAdvisorFactory.class
)
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 根據不同的註解類型封裝不同的增強器
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
前置增強
從上面的函數中我們看到,Spring會根據不同的註解生成不同的增強器,具體表現在了switch (aspectJAnnotation.getAnnotationType())
,根據不同的類型來生成。例如在AtBefore會對應AspectJMethodBeforeAdvice,早AspectJMethodBeforeAdvice中完成了增強邏輯,
並且這裡的**AspectJMethodBeforeAdvice**最後被適配器封裝成**MethodBeforeAdviceInterceptor**,
如何被封裝的 這有機再在分析。
我們先看一下MethodBeforeAdviceInterceptor的代碼
- 看源碼
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
其中上述代碼的MethodBeforeAdvice
代表的前置增強的AspectJMethodBeforeAdvice
,根據before
方法來到這個類。
- 看源碼(具體實現在
AspectJMethodBeforeAdvice.java
)
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
// 直接調用增強方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
繼續跟蹤函數體內的invokeAdviceMethod
方法
- 看源碼(具體實現在
AbstractAspectJAdvice.java
)
protected Object invokeAdviceMethod(
@Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
throws Throwable {
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
接着繼續根據函數體內的invokeAdviceMethodWithGivenArgs
方法,
- 看源碼(具體實現在
AbstractAspectJAdvice.java
)
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// 通過反射調用AspectJ註解類中的增強方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
invokeAdviceMethodWithGivenArgs方法中的aspectJAdviceMethod正是對前置增強的方法,在這裡實現了調用。
簡單總結:
前置通知的大致過程是在攔截器鏈中放置MethodBeforeAdviceInterceptor,而在MethodBeforeAdvivceInterceptor中又放置了AspectJMethodBeforeAdvice,並在調用invoke時首先串聯調用。
後置增強
相比前置增強略有不同,後置增強沒有提供中間的類,而是直接在攔截器中使用過了中間的
AspectJAfterAdvice
,也就是直接實現了MethodInterceptor
。
- 看源碼(AspectJAfterAdvice.java)
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
public AspectJAfterAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
// 激活增強方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
@Override
public boolean isBeforeAdvice() {
return false;
}
@Override
public boolean isAfterAdvice() {
return true;
}
}
其他的幾個增強器,下次具體來看
尋找匹配的增強器
前面的函數中已經完成了所有增強器的解析,也就是講解完了關於`findCandidateAdvisors`方法;但是對於所有增強器來講,並不一定都適用於當前的bean,還要取出適合的增強器,也就是滿足我們配置的通配符的增強器,具體實現在`findAdvisorsThatCanAply`中,我們需要回到最初的**AbstractAdvisorAuroProxyCreator**類中,然後進入到findEligibleAdvisors函數內的**findAdvisorsThatCanAply**方法的實現:
- 看源碼(
AbstractAdvisorAuroProxyCreator.java
)
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 過濾已經得到的advisors
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
繼續跟蹤findAdvisorsThatCanApply
方法:
- 看源碼(
AOPUtils.java
)
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 首先處理引介增強
/*
* 引介增強是一種特殊的增強,其它的增強是方法級別的增強,即只能在方法前或方法後添加增強。
* 而引介增強則不是添加到方法上的增強, 而是添加到類方法級別的增強,即可以為目標類動態實現某個接口,
* 或者動態添加某些方法。我們通過下面的事例演示引介增強的使用
*/
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 對於普通bean的 進行處理
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply函數的主要功能時尋找增強器中適用於當前class的增強器。引介增強與普通增強的處理是不一樣的,所以分開處理。而對於真正的匹配在canApply
中實現。
接着跟蹤canApply
方法
- 看源碼(AopUtils.java)
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// 通過Pointcut的條件判斷此類是否匹配
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 反射獲取類中所有的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 根據匹配原則判斷該方法是否能匹配Pointcut中的規則,如果有一個方法匹配則返回true
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
- 源碼分析
首先會判斷bean是否滿足切點的規則,如果能滿足,則獲取bean的所有方法,判斷是否有方法能夠匹配規則,有方法匹配規則就代表Advisor能作用於該bean,該方法就會返回true,然後findAdvisorsThatCanApply
函數就會將Advisor加入到eligibleAdvisors中。
最後我們以註解的規則來看一下bean的method是怎樣匹配Pointcut中的規則的
- 看源碼(
AnnotationMethodMatcher.java
)
@Override
public boolean matches(Method method, Class<?> targetClass) {
if (matchesMethod(method)) {
return true;
}
// Proxy classes never have annotations on their redeclared methods.
if (Proxy.isProxyClass(targetClass)) {
return false;
}
// The method may be on an interface, so let's check on the target class as well.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
return (specificMethod != method && matchesMethod(specificMethod));
}
private boolean matchesMethod(Method method) {
// 可以看出判斷該Advisor是否使用於bean中的method,只需看method上是否有Advisor的註解
return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) :
method.isAnnotationPresent(this.annotationType));
}
至此:在後置處理器中找到了所有匹配Bean中的增強器,