Spring AOP(三)【源码分析】基于注解的AOP——第1、2步:解析配置、获取目标Advisor


本系列主要分析基于注解形式的SpringAOP实现流程,大致可以分为以下几个核心步骤:

  • 解析配置aspectj-autoproxy
  • 加载Aspect切面和Advisor增强器
  • 创建代理
  • 调用代理对象中的方法
对于注解形式的SpringAOP实现流程,首先需要获取到针对于目标Bean的Advisor增强器。
在解析xml配置时,我们配置了<aop:aspectj-autoproxy/>,将会注册一个postProcessor。
在Bean的初始化之后,进行两个操作:
	1.通过遍历全部注册的带@Aspect注解的Bean,解析相关信息,创建Advisor;
	2.找到用于当前Bean的Advisor:根据ClassFilter和MethodMatcher过滤

第一步:解析配置aspectj-autoproxy

在使用基于注解形式的AOP时,我们需要在xml文件中增加一项配置:

<aop:aspectj-autoproxy/>

代表了框架将会自动识别并处理@Aspect等注解。
此标签使用AspectJAutoProxyBeanDefinitionParser来解析,有两个步骤:

  • 注册 AnnotationAwareAspectJAutoProxyCreator,这个类负责了切面类的解析、代理对象的创建,是AOP的核心类。
  • 解析<aop:aspectj-autoproxy /> 的两个属性:
    1. expose-proxy是否暴露当前代理对象为ThreadLocal模式
      Spring文档中指明:对于方法的拦截只限于public,而不会拦截protected和private方法(如果有需求,可以使用AspectJ框架);另外对于public方法内部调用的其他方法也不会进行拦截,如果有这个需求,则可以配置expose-proxy参数来实现。
    2. proxy-target-class
      该属性默认为false,当我们配置为true时,代表指定使用CGLib动态代理方式实现增强。

第二步:加载Aspect切面和Advisor

postProcessBeforeInstantiation

AnnotationAwareAspectJAutoProxyCreator虽然是以Creater结尾的,但它其实实现了PostProcessor的接口。

BeanPostProcessor 
    |
    ├── InstantiationAwareBeanPostProcessor
    |       |
    |       ├── SmartInstantiationAwareBeanPostProcessor
    |       |       |
    |       |       ├── AbstractAutoProxyCreator
    |       |       |       |
    |       |       |       ├── BeanNameAutoProxyCreator
    |       |       |       ├── AbstractAdvisorAutoProxyCreator
    |       |       |       |       |
    |       |       |       |       ├── DefaultAdvisorAutoProxyCreator
    |       |       |       |       ├── InfrastructureAdvisorAutoProxyCreator
    |       |       |       |       ├── AspectJAwareAdvisorAutoProxyCreator
    |       |       |       |       |       |
    |       |       |       |       |       ├── AnnotationAwareAspectJAutoProxyCreator

在Ioc分析的过程中,我们知道PostProcessor会在Bean的实例化之前,调用postProcessBeforeInstantiation方法,作用是当有AOP的需要时提前短路返回一个代理对象,替代原本的正常实例化流程。
Spring IOC(三)createBean方法源码分析
中第2-3步:applyBeanPostProcessorsBeforeInstantiation)

那么就从postProcessBeforeInstantiation的实现看起,AnnotationAwareAspectJAutoProxyCreator中此接口是在其父类AbstractAutoProxyCreator中被实现:

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		if (beanName != null) {
			TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
			if (targetSource != null) {
				this.targetSourcedBeans.add(beanName);
				Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
				Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
				this.proxyTypes.put(cacheKey, proxy.getClass());
				return proxy;
			}
		}
		return null;
	}

在这个方法中会进行一个getCustomTargetSource的判断,即自定义的TargetSource,如果存在,则在此处创建代理而代替正常的实例化流程,TargetSource将以自定义方式处理目标实例。有关TargetSource见附1.

postProcessAfterInitialization

上述postProcessBeforeInstantiation方法会返回null,即进行正常的实例化流程。
在Ioc分析的过程中,我们知道PostProcessor会在Bean的初始化之后,调用postProcessAfterInitialization方法
Spring IOC(四)doCreateBean方法源码分析
中第5-4步:applyBeanPostProcessorsAfterInitialization)

那么就从postProcessAfterInitialization的实现看起:

/**
	 * 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(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

进入到wrapIfNecessary方法:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return 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;
	}

在这个方法中可见关键步骤有两个:

  1. getAdvicesAndAdvisorsForBean,也就是本节重点:加载Aspect切面Advice通知。
  2. createProxy创建代理

本节重点分析getAdvicesAndAdvisorsForBean方法:

关键方法:getAdvicesAndAdvisorsForBean

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

findEligibleAdvisors:

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

在这个方法中关键步骤有:

  • findCandidateAdvisors:获取所有Advisors
  • findAdvisorsThatCanApply:找可以应用到当前BeanName的Advisors
  • sortAdvisors:给Advisors排序

1.findCandidateAdvisors获取所有Advisors

这个方法在AnnotationAwareAspectJAutoProxyCreator类中有实现

@Override
	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		return advisors;
	}
  1. 调用父类方法super.findCandidateAdvisors(),意义为 加载xml配置文件 中的Advisor
  2. aspectJAdvisorsBuilder.buildAspectJAdvisors(),才是获取 注解形式 的Advisor

xml形式的获取步骤可以概括为:

  • 从容器中查找 Advisor类型的BeanName
  • 通过getBean()获取对应的Bean,并添加到Advisors中

我们主要来看注解形式Advisor的获取:

public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = null;

		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				List<Advisor> advisors = new LinkedList<Advisor>();
				aspectNames = new LinkedList<String>();
				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
					Class<?> beanType = this.beanFactory.getType(beanName);
					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);
							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<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. 遍历找到带有@Aspect的Bean
  3. 通过有@Aspect的Bean获取Advisors

1.1.获取在工厂中注册的所有BeanName

1.2.遍历找到带有@Aspect的Bean

1.3.在Aspect注解的Bean中获取Advisors

即上段中的:
List classAdvisors = this.advisorFactory.getAdvisors(factory);

@Override
	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<Advisor>();
		for (Method method : getAdvisorMethods(aspectClass)) {
			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;
	}

其中 getAdvisorMethods(aspectClass)方法:

private List<Method> getAdvisorMethods(Class<?> aspectClass) {
		final List<Method> methods = new LinkedList<Method>();
		ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
			@Override
			public void doWith(Method method) throws IllegalArgumentException {
				// Exclude pointcuts
				if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
					methods.add(method);
				}
			}
		});
		Collections.sort(methods, METHOD_COMPARATOR);
		return methods;
	}

可知在这里做了处理:声明为pointcuts的方法不做处理。
获取到此aspectClass的其他所有方法后,再提取Advisor:
getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName)

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
			int declarationOrderInAspect, String aspectName) {

		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}

		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}

有两个步骤:

  1. getPointcut:获取切点注解信息
  2. 根据切点注解信息生成Advisor

1.3.1. getPointcut获取切点Pointcut中的注解信息

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		AspectJExpressionPointcut ajexp =
				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
		return ajexp;
	}

其中findAspectJAnnotationOnMethod:

protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
		Class<?>[] classesToLookFor = new Class<?>[] {
				Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
		for (Class<?> c : classesToLookFor) {
			AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
			if (foundAnnotation != null) {
				return foundAnnotation;
			}
		}
		return null;
	}

表示获取标记为Before、Around、After、 AfterReturning、AfterThrowing、Pointcut的注解信息aspectJAnnotation;

然后看这一步:

ajexp.setExpression(aspectJAnnotation.getPointcutExpression());

意义为在得到的aspectJAnnotation中,解析PointCut标记的注解表达式。
举个例子,Spring AOP(一)Spring AOP实现原理简介中Demo的切面类AopAspect,getPointcutExpression这里得到的就是@Pointcut(“execution(* example.aop..(…))”)中的:execution(* example.aop..(…));

AspectJExpressionPointcut ajexp =
				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());

最后将传来参数candidateAspectClass:Aspect切面中除PointCut之外的注解,与此PointcutExpression进行一个包装。
举个栗子就是上述Demo中 @Before(“aopPointcut()”)被解析为 @Before("*example.aop…(…))")的信息。

1.3.2.根据切点注解信息生成Advisor

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		this.declaredPointcut = declaredPointcut;
		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;
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}

此方法的前半部分是单纯的赋值,重点在于instantiateAdvice(this.declaredPointcut)这一行:

private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
		return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
	}

getAdvice的实现:

@Override
	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 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;
			case AtAround:
				springAdvice = new AspectJAroundAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				return null;
			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;
	}

因为获取到的注解信息有Before、After等不同的增强方式,所以也需要不同的Advisor来完成不同的逻辑,这个方法正是实现了这个功能。方法逻辑很清晰,分为了5种Advisor的创建:

  • AspectJMethodBeforeAdvice
  • AspectJAfterAdvice
  • AspectJAfterReturningAdvice
  • AspectJAfterThrowingAdvice
  • AspectJAroundAdvice

//常用的Advisor内部实现后续再详细分析

2.findAdvisorsThatCanApply找匹配当前Bean的Advisors

protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

方法中的入参candidateAdvisors即为上一步获取的全部Advisor,beanClass为当前Bean类型,然后对Advisors进行选择。
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) {
				// already processed
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

Spring AOP(二)AOPAlliance与SpringAOP核心接口介绍中的(5. Spring新增接口:Advisor 通知器)中所描述,Spring AOP新增了一个接口Advisor,用来包装 Advice通知 和 Pointcut切点 两个对象。而Advisor的实现分为了两种:PointcutAdvisor和IntroductionAdvisor。

在这个方法中,对于Advisor分为了两种:

  • IntroductionAdvisor
    是类级别增强,因此只需要直接持有ClassFilter即可.见附2.
  • PointcutAdvisor,方法级别增强
    是方法级别增强,因此需要同时使用ClassFilter和MethodMatcher(方法匹配器)。PointcutAdvisor内部持有一个Pointcut ,而Pointcut就是由ClassFilter和MethodMatcher组成的。

最终,我们在工厂所有的Advisors中,获取到可应用于当前Bean的一组Advisors。

下面是两种Advisor对于当前Bean是否匹配的代码,逻辑清晰不做叙述。

2.1. Introduction类型的Advisor的选择

  • 获取Advisor中的ClassFilter,匹配当前targetClass
canApply(candidate, clazz)
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
		return canApply(advisor, targetClass, false);
	}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		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;
		}
	}

2.2. Pointcut类型的Advisor的选择

  • 获取advisor中持有的Pointcut
  • 获取Pointcut中的ClassFilter,匹配当前targetClass
  • 获取Pointcut中的MethodMatcher,遍历匹配当前targetClass中所有的method
canApply(candidate, clazz, hasIntroductions)
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		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;
		}
	}
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();
		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		classes.add(targetClass);
		for (Class<?> clazz : classes) {
			Method[] methods = clazz.getMethods();
			for (Method method : methods) {
				if ((introductionAwareMethodMatcher != null &&
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

*流程图总结

在这里插入图片描述

附1.TargetSource

其实,SpringAOP代理的不是Target,而是TargetSource
TargetSource接口:

public interface TargetSource extends TargetClassAware {

	@Override
	Class<?> getTargetClass();

	boolean isStatic();

	Object getTarget() throws Exception;

	void releaseTarget(Object target) throws Exception;

}

通常情况下,一个Proxy只能代理一个Target,但如果让Proxy通过TargetSource来获取目标Bean,可以通过TargetSource的内部逻辑来实现每次获取的Target都不同。

  • 如果是static的TargetSource,则每次都返回相同的Target;
  • 如果是dynamic的TargetSource,则可以支持pooling(目标对象池), hot swapping(运行时目标对象热替换)等功能。

我们不必在编码中直接去实现TargetSource接口,Spring AOP框架为我们提供了一个默认的实现类:SingletonTargetSource ,这个目标源取得的目标对象是单例的。

附2.PointcutAdvisor与IntroductionAdvisor

两者都是对Spring中Advisor接口的继承:

Advisor 
   |
   ├── PointcutAdvisor
   ├── IntroductionAdvisor
  • PointcutAdvisor
    和切点有关的Advisor,主要为了拦截方法,这种增强属于方法级别的增强。
  • IntroductionAdvisor
    和切点无关,IntroductionAdvisor主要为了给targetClass 追加接口 (或者说追加更多的方法),这种增强属于类级别的增强。

IntroductionAdvisor类型是什么时候获取的?
上文(1.3.在Aspect注解的Bean中获取Advisors)中,可以看到有段代码:

// Find introduction fields.
		for (Field field : aspectClass.getDeclaredFields()) {
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

在这个部分,将IntroductionAdvisor与PointcutAdvisor一起加入到了候选Advisors中。

IntroductionAdvisor的使用并不多见,使用 IntroductionAdvisor的Demo:

<context:component-scan base-package="example.aop"/>
    <aop:aspectj-autoproxy/>

被代理类

public interface TestAop {

    void process();
}

@Component
public class TestAopImpl implements TestAop {
    @Override
    public void process() {
        System.out.println("testAop.process()");
    }
}

引介代理类:

public interface Introduction {

    void introductionMethod();
}
@Component
public class IntroductionImpl implements Introduction {

    @Override
    public void introductionMethod() {
        System.out.println("引入方法");
    }
}

切面类:

@Component
@Aspect
public class AopAspect {

    @DeclareParents(value = "example.aop.TestAop+",
            defaultImpl = IntroductionImpl.class)
    private Introduction introduction;
}

测试类:

 public static void main(final String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
        TestAop testAop = ac.getBean(TestAop.class);
        testAop.process();
        Introduction introduction = (Introduction) testAop;
        introduction.introductionMethod();
        }

输出结果:

testAop.process()
引入方法
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值