SpringAop原始碼分析(基於註解)二:篩選通知器
在上篇文章SpringAop原始碼分析(基於註解)一中,我們分析了Spring是怎樣把專門處理AOP的類進行註冊的,本篇文章我們將分析這個類是怎麼對AOP起作用的。
一、入口
我們已經知道BeanPostProcessors
是在Bean例項化前後起作用的,如果看過前面的文章Spring Ioc原始碼分析 之 Bean的載入(八):初始化,應該知道Spring是在AbstractAutowireCapableBeanFactory#doCreateBean()
方法中有一個初始化Bean的方法:
exposedObject = initializeBean(beanName,exposedObject,mbd)
複製程式碼
繼續深入:
protected Object initializeBean(final String beanName,final Object bean,@Nullable RootBeanDefinition mbd) {
//JDK的安全機制驗證許可權
if (System.getSecurityManager() != null) {
// <1> 啟用 Aware 方法,對特殊的 bean 處理:Aware、BeanClassLoaderAware、BeanFactoryAware
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName,bean);
return null;
},getAccessControlContext());
}
else {
// <1> 啟用 Aware 方法,對特殊的 bean 處理:Aware、BeanClassLoaderAware、BeanFactoryAware
invokeAwareMethods(beanName,bean);
}
Object wrappedBean = bean;
// <2> 後置處理器,before
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
}
// <3> 啟用使用者自定義的 init 方法
try {
invokeInitMethods(beanName,wrappedBean,mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),beanName,"Invocation of init method failed",ex);
}
// <2> 後置處理器,after
if (mbd == null || !mbd.isSynthetic()) {
// 我們關注的重點是這裡!!!
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);
}
return wrappedBean;
}
複製程式碼
其中第<2>步就是觸發我們BeanPostProcessors
的地方。
我們再回過頭來看AnnotationAwareAspectJAutoProxyCreator
有一個上層父類AbstractAutoProxyCreator
,它實現了SmartInstantiationAwareBeanPostProcessor介面,來看下它的主要方法。
//AbstractAutoProxyCreator.java
//在Bean初始化之前回調
@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
*/
//在Bean初始化之後回撥
@Override
public Object postProcessAfterInitialization(@Nullable Object bean,String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(),beanName);
//判斷快取中是否有
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 沒有,為 bean 生成代理物件
return wrapIfNecessary(bean,cacheKey);
}
}
return bean;
}
複製程式碼
可以看到AbstractAutoProxyCreator
類裡實現了postProcessAfterInitialization()
方法,該方法將在Bean初始化之後呼叫。
接著看wrapIfNecessary方法:
//AbstractAutoProxyCreator.java
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;
}
/*
* 如果是基礎設施類(Pointcut、Advice、Advisor 等介面的實現類),或是應該跳過的類,
* 則不應該生成代理,此時直接返回 bean
*/
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(),beanName)) {
this.advisedBeans.put(cacheKey,Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 返回匹配當前 bean 的所有的通知器 advisor、advice、interceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(),null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey,Boolean.TRUE);
// 核心!建立代理物件
Object proxy = createProxy(
bean.getClass(),specificInterceptors,new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey,proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey,Boolean.FALSE);
return bean;
}
複製程式碼
這裡看起來邏輯不復雜:
- 找到匹配該Bean的所有通知器
- 建立代理物件
但是這兩步具體細節就很複雜了,我們一個一個來看,先看第一步。
二、找到匹配該Bean的所有通知器
//AbstractAdvisorAutoProxyCreator
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass,@Nullable TargetSource targetSource) {
//獲取匹配的通知器
List<Advisor> advisors = findEligibleAdvisors(beanClass,beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
複製程式碼
繼續深入:
//AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass,String beanName) {
//獲取所有的通知器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//篩選可應用在 beanClass 上的 Advisor,通過 ClassFilter 和 MethodMatcher
//對目標類和方法進行匹配
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors,beanClass,beanName);
//
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//設定排序,方便後面攔截器鏈執行
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
複製程式碼
2.1、獲取有所通知器
接上面的程式碼:
//AnnotationAwareAspectJAutoProxyCreator.java
protected List<Advisor> findCandidateAdvisors() {
// 呼叫父類方法從容器中獲取所有的通知器
List<Advisor> advisors = super.findCandidateAdvisors();
// 解析 @Aspect 註解,並構建通知器
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
複製程式碼
2.1.1、呼叫父類方法從容器中獲取所有的通知器
先看一下呼叫父類的方法
//AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null,"No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
複製程式碼
繼續深入:
//BeanFactoryAdvisorRetrievalHelper.java
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = null;
synchronized (this) {
// cachedAdvisorBeanNames 是 advisor 名稱的快取
advisorNames = this.cachedAdvisorBeanNames;
//如果快取為空,到容器中查詢,
//並設定快取,後續直接使用快取即可
if (advisorNames == null) {
// 從容器中查詢 Advisor 型別 bean 的名稱
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory,Advisor.class,true,false);
// 設定快取
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
// 遍歷 advisorNames
for (String name : advisorNames) {
if (isEligibleBean(name)) {
// 忽略正在建立中的 advisor bean
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
//呼叫 getBean 方法從容器中獲取名稱為 name 的 bean,
//並將 bean 新增到 advisors 中
advisors.add(this.beanFactory.getBean(name,Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
複製程式碼
這段程式碼雖然很長,但並不複雜:
-
先從快取中獲取,獲取不到就從IOC容器中獲取型別為
Advisor
的BeanName -
遍歷獲取到的BeanName,呼叫getBean()方法獲取例項,並加入到通知器集合中
2.1.2、解析 @Aspect 註解,並構建通知器
程式碼如下:
//BeanFactoryAspectJAdvisorsBuilder.java
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<>();
aspectNames = new LinkedList<>();
// 從容器中獲取所有 bean 的名稱
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory,Object.class,false);
for (String beanName : beanNames) {
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.
// 根據 beanName 獲取 bean 的型別
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 檢測 beanType 是否包含 Aspect 註解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
//建立Aspect元資料
AspectMetadata amd = new AspectMetadata(beanType,beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//建立元資料aop例項化工廠
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 LinkedList<>();
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;
}
複製程式碼
程式碼很長,但我們在只需要關注關鍵步驟即可:
- 從容器中獲取所有 bean 的名稱
- 遍歷,根據 beanName 獲取 bean 的型別
- 檢測 beanType 是否包含 Aspect 註解
- 從工廠中獲取通知器
這裡也可以和我們前面的demo對應起來,我們之前定義了一個LogAspect
的類,然後用註解@Component
和@Aspect
宣告瞭。
上面這段程式碼的邏輯就是:找到這個標註@Aspect
的類,並找到裡面定義的通知器,如@Before
、@After
等。
同時這也回答了上篇文章的一個問題:Spring是怎麼找到我們定義的切面的?
@Aspect
@Component
@EnableAspectJAutoProxy
public class LogAspect {
@Before("execution(* com.mydemo.work.StudentController.getName(..))")
public void doBefore() {
System.out.println("========before");
}
@After("execution(* com.mydemo.work.StudentController.getName(..))")
public void doAfter() {
System.out.println("========after");
}
}
複製程式碼
接著看從工廠獲取通知器的方法this.advisorFactory.getAdvisors(factory)
//ReflectiveAspectJAdvisorFactory.java
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 LinkedList<>();
<1> //獲取該切面的所有方法,排除@Pointcut修飾的
for (Method method : getAdvisorMethods(aspectClass)) {
//遍歷,獲取被 通知註解 修飾的方法,並封裝成Advisor
<2> Advisor advisor = getAdvisor(method,lazySingletonAspectInstanceFactory,advisors.size(),aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect,emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
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()
方法:
public Advisor getAdvisor(Method candidateAdviceMethod,MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect,String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
//獲取切點Pointcut
<3> AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod,aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 建立 Advisor 實現類,封裝切點表示式、通知名稱、方法名稱等
<6> return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut,candidateAdviceMethod,this,aspectInstanceFactory,declarationOrderInAspect,aspectName);
}
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod,Class<?> candidateAspectClass) {
// 獲取方法上的 AspectJ 相關註解,包括 @Before,@After、@Around、@Pointcut 等
//因為這些註解上都可以設定切點
<4> AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass,new String[0],new Class<?>[0]);
<5> //設定切點匹配表示式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
複製程式碼
這裡的邏輯其實也不復雜,。
-
<1>,獲取切面中的所有方法,排除@Pointcut修飾的方法
-
<2>,遍歷所有方法
-
<3>,獲取該方法的切點
-
<4>,根據AspectJ相關註解,包括 @Before,@After、@Pointcut等獲取切點
-
<5>,設定切點表示式到AspectJExpressionPointcut 封裝結果如下:
- <6>,建立Advisor,封裝切點表示式、通知名稱、方法名稱等
封裝結果如下:
this.advisorFactory.getAdvisors(factory)
這段程式碼的最終目的,就是獲取該切面所有的通知方法、它們的切點,並把它們都封裝成一個個Advisor
。
但其實每個Advisor
裡的Advice
都是不同的,我們來看下建立Advisor
的過程,即第<6>步:
//InstantiationModelAwarePointcutAdvisorImpl.java
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,Method aspectJAdviceMethod,AspectJAdvisorFactory aspectJAdvisorFactory,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);
}
}
複製程式碼
上面是 InstantiationModelAwarePointcutAdvisorImpl
的構造方法,不過我們無需太關心這個方法中的一些初始化邏輯。我們把目光移到構造方法的最後一行程式碼中,即 instantiateAdvice(this.declaredPointcut)
,這個方法用於建立通知 Advice。
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod,pcut,this.aspectInstanceFactory,this.declarationOrder,this.aspectName);
}
public Advice getAdvice(Method candidateAdviceMethod,AspectJExpressionPointcut expressionPointcut,String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 獲取 Advice 註解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
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;
// 按照註解型別生成相應的 Advice 實現類
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore: // @Before -> AspectJMethodBeforeAdvice
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod,expressionPointcut,aspectInstanceFactory);
break;
case AtAfter: // @After -> AspectJAfterAdvice
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod,aspectInstanceFactory);
break;
case AtAfterReturning: // @AfterReturning -> AspectJAfterAdvice
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod,aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing: // @AfterThrowing -> AspectJAfterThrowingAdvice
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod,aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround: // @Around -> AspectJAroundAdvice
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod,aspectInstanceFactory);
break;
//什麼都不做,直接返回 null。
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
//獲取方法的引數列表名稱,比如方法 int sum(int numX,int numY),
//getParameterNames(sum) 得到 argNames = [numX,numY]
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 設定引數名
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
複製程式碼
可見,根據註解的不同,建立不同的Advice
,並封裝到Advisor
中。
2.2、篩選合適的通知器
現在我們已經拿到了所有通知器,接下來就要篩選出匹配當前Bean的通知器。
程式碼List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors,beanName);
中:
//AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors,Class<?> beanClass,String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
//篩選匹配的通知器
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors,beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
複製程式碼
繼續深入:
//AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors,String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
//篩選出匹配當前Bean的通知器
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors,beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
複製程式碼
//AopUtils.java
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors,Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<>();
// 篩選 IntroductionAdvisor 型別的通知器
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;
}
複製程式碼
//AopUtils.java
public static boolean canApply(Advisor advisor,Class<?> targetClass,boolean hasIntroductions) {
//ClassFilter直接匹配
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;
}
}
複製程式碼
//AopUtils.java
public static boolean canApply(Pointcut pc,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;
}
//查詢當前類及其父類(以及父類的父類等等)所實現的介面,由於介面中的方法是 public,
//所以當前類可以繼承其父類,和父類的父類中所有的介面方法
Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
// 獲取當前類的方法列表,包括從父類中繼承的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 使用 methodMatcher 匹配方法,匹配成功即可立即返回
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method,hasIntroductions)) ||
methodMatcher.matches(method,targetClass)) {
return true;
}
}
}
return false;
}
複製程式碼
上面就是篩選通知器的過程,篩選的工作主要由 ClassFilter 和 MethodMatcher 來完成。關於 ClassFilter 和 MethodMatcher,在 AOP 中,切點 Pointcut 是用來匹配連線點的,以 AspectJExpressionPointcut 型別的切點為例。該型別切點實現了ClassFilter 和 MethodMatcher 介面,匹配的工作則是由 AspectJ 表示式解析器負責。除了使用 AspectJ 表示式進行匹配,Spring 還提供了基於正則表示式的切點類,以及更簡單的根據方法名進行匹配的切點類。大家有興趣的話,可以自己去了解一下,這裡就不多說了。
現在,我們知道了通知是怎麼建立和篩選的。那下篇文章,我們一起來分析一下AOP是怎麼建立代理物件的。
總結
這篇文章花了比較大的功夫,受個人能力限制,很遺憾沒有對裡面的原始碼作非常詳細的分析,只理解了主流程,希望朋友們發現文章中的錯誤或不妥之處,還請指出,互相交流~