SpringAop源碼分析(基於註解)二:篩選通知器

在上篇文章SpringAop源碼分析(基於註解)一中,咱們分析了Spring是怎樣把專門處理AOP的類進行註冊的,本篇文章咱們將分析這個類是怎麼對AOP起做用的。java

1、入口

咱們已經知道BeanPostProcessors是在Bean實例化先後起做用的,若是看過前面的文章Spring Ioc源碼分析 之 Bean的加載(八):初始化,應該知道Spring是在AbstractAutowireCapableBeanFactory#doCreateBean() 方法中有一個初始化Bean的方法:正則表達式

exposedObject = initializeBean(beanName, exposedObject, mbd)
複製代碼

繼續深刻:spring

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的地方。express

咱們再回過頭來看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, beanName, 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(), 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;
	}
複製代碼

這裏看起來邏輯不復雜:app

  • 找到匹配該Bean的全部通知器
  • 建立代理對象

可是這兩步具體細節就很複雜了,咱們一個一個來看,先看第一步。ide

2、找到匹配該Bean的全部通知器

//AbstractAdvisorAutoProxyCreator

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();
	}
複製代碼

繼續深刻:源碼分析

//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.一、獲取有所通知器

接上面的代碼:post

//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.一、調用父類方法從容器中獲取全部的通知器

先看一下調用父類的方法

//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.二、解析 @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, true, 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, 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);
	}
	}
複製代碼

上面是 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, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, 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, expressionPointcut, aspectInstanceFactory);
            break;

        case AtAfterReturning:    // @AfterReturning -> AspectJAfterAdvice
            springAdvice = new AspectJAfterReturningAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;

        case AtAfterThrowing:    // @AfterThrowing -> AspectJAfterThrowingAdvice
            springAdvice = new AspectJAfterThrowingAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;

        case AtAround:    // @Around -> AspectJAroundAdvice
            springAdvice = new AspectJAroundAdvice(
                    candidateAdviceMethod, expressionPointcut, 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.二、篩選合適的通知器

如今咱們已經拿到了全部通知器,接下來就要篩選出匹配當前Bean的通知器。 代碼List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, 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, Class<?> beanClass, 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, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(pc, "Pointcut must not be null");
	if (!pc.getClassFilter().matches(targetClass)) {
		return false;
	}

	MethodMatcher methodMatcher = pc.getMethodMatcher();
	if (methodMatcher == MethodMatcher.TRUE) {
		// No need to iterate the methods if we're matching any method anyway...
		return true;
	}

	IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
	if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
		introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
	}

	//查找當前類及其父類(以及父類的父類等等)所實現的接口,因爲接口中的方法是 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, targetClass, hasIntroductions)) ||
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}

	return false;
	}
複製代碼

上面就是篩選通知器的過程,篩選的工做主要由 ClassFilter 和 MethodMatcher 來完成。關於 ClassFilter 和 MethodMatcher,在 AOP 中,切點 Pointcut 是用來匹配鏈接點的,以 AspectJExpressionPointcut 類型的切點爲例。該類型切點實現了ClassFilter 和 MethodMatcher 接口,匹配的工做則是由 AspectJ 表達式解析器負責。除了使用 AspectJ 表達式進行匹配,Spring 還提供了基於正則表達式的切點類,以及更簡單的根據方法名進行匹配的切點類。你們有興趣的話,能夠本身去了解一下,這裏就很少說了。

如今,咱們知道了通知是怎麼建立和篩選的。那下篇文章,咱們一塊兒來分析一下AOP是怎麼建立代理對象的。

總結

這篇文章花了比較大的功夫,受我的能力限制,很遺憾沒有對裏面的源碼做很是詳細的分析,只理解了主流程,但願朋友們發現文章中的錯誤或不妥之處,還請指出,互相交流~

參考:
www.tianxiaobo.com/2018/06/20/…

相關文章
相關標籤/搜索