当前位置: 首页 > article >正文

spring 中 AspectJ 基于 XML 的实现分析

前面的文章介绍了 spring 引入 AspectJ 之后,基于注解实现 AOP 的过程分析,今天我们来看下AspectJ 基于 XML 的 AOP 实现逻辑。

XML 的实现示例可以参考 AspectJ 对于 AOP 的实现。

aop:config 标签解析

先去 spring-aop 模块下,META-INF/spring.handlers 中查看 aop 命名空间对应的处理器为 AopNamespaceHandler。在 AopNamespaceHandler#init 方法中发现为 config 标签注册的解析器为 org.springframework.aop.config.ConfigBeanDefinitionParser。

// ConfigBeanDefinitionParser
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
	CompositeComponentDefinition compositeDef =
			new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
	parserContext.pushContainingComponent(compositeDef);

	// 配置自动代理生成器
	configureAutoProxyCreator(parserContext, element);

	// 解析 aop:config 子节点
	List<Element> childElts = DomUtils.getChildElements(element);
	for (Element elt: childElts) {
		String localName = parserContext.getDelegate().getLocalName(elt);
		if (POINTCUT.equals(localName)) {
			parsePointcut(elt, parserContext);
		}
		else if (ADVISOR.equals(localName)) {
			parseAdvisor(elt, parserContext);
		}
		else if (ASPECT.equals(localName)) {
			parseAspect(elt, parserContext);
		}
	}

	parserContext.popAndRegisterContainingComponent();
	return null;
}

主要逻辑如下:

  1. 配置自动代理生成器
  2. 解析 aop:config 标签子节点

配置自动代理生成器

private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
	AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
public static void registerAspectJAutoProxyCreatorIfNecessary(
		ParserContext parserContext, Element sourceElement) {
	// 注册一个 beanClass 为 AspectJAwareAdvisorAutoProxyCreator 的 BeanDefinition 
	BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
			parserContext.getRegistry(), parserContext.extractSource(sourceElement));
	// 处理 proxy-target-class 和 expose-proxy 两个属性
	useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
	registerComponentIfNecessary(beanDefinition, parserContext);
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

其实就是在 BeanFactory 中注册一个 beanClass 为 AspectJAwareAdvisorAutoProxyCreator 的 BeanDefinition,如果 aop:config 设置了 proxy-target-class 和 expose-proxy 两个属性,则为这个注册的 BeanDefinition 也设置这两个属性,添加 proxyTargetClass 和 exposeProxy 到 propertyValues 中,供 bean 对象创建时使用。

解析 config 标签子节点

aop:config 共支持三种类型的子节点。分别如下:

  • pointcut 定义切入点,配置切入点表达式
  • advisor 自定义 Advisor,需要一个 Advice
  • aspect 需对应一个切面类

在 ConfigBeanDefinitionParser#parse 中定义了三个分支分别解析对应的子节点 。

pointcut

// ConfigBeanDefinitionParser
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
	// 获取 pointcut 标签 id 和 expression 两个属性
	String id = pointcutElement.getAttribute(ID);
	String expression = pointcutElement.getAttribute(EXPRESSION);

	AbstractBeanDefinition pointcutDefinition = null;

	try {
		this.parseState.push(new PointcutEntry(id));
		// 一个 pointcut 标签对应一个 AspectJExpressionPointcut
		pointcutDefinition = createPointcutDefinition(expression);
		pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

		// 将配置 id 作为 beanName,注册创建的 BeanDefinition,不存在 id,会生成一个 beanName 之后,进行注册
		String pointcutBeanName = id;
		if (StringUtils.hasText(pointcutBeanName)) {
			parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
		}
		else {
			pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
		}

		parserContext.registerComponent(
				new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
	}
	finally {
		this.parseState.pop();
	}

	return pointcutDefinition;
}

// 创建 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
	RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
	beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
	beanDefinition.setSynthetic(true);
	beanDefinition.getPropertyValues().add(EXPRESSION, expression);
	return beanDefinition;
}

解析 pointcut 标签目的,就是创建 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition 进行注册。我们知道,AspectJExpressionPointcut 是连接 spring 和 AspectJ 的桥梁,必须需要一个切入点表达式,所以可以看到为注册的 BeanDefinition 设置了一个 expression 属性。

advisor

// ConfigBeanDefinitionParser
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
	// advisor --> BeanDefinition
	AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
	String id = advisorElement.getAttribute(ID);

	try {
		this.parseState.push(new AdvisorEntry(id));
		// 注册
		String advisorBeanName = id;
		if (StringUtils.hasText(advisorBeanName)) {
			parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
		}
		else {
			advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
		}
		
		// 解析 advisor 标签下的 pointcut 属性,为 advisorDef 设置属性
		Object pointcut = parsePointcutProperty(advisorElement, parserContext);
		if (pointcut instanceof BeanDefinition) {
			advisorDef.getPropertyValues().add(POINTCUT, pointcut);
			parserContext.registerComponent(
					new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
		}
		else if (pointcut instanceof String) {
			advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
			parserContext.registerComponent(
					new AdvisorComponentDefinition(advisorBeanName, advisorDef));
		}
	}
	finally {
		this.parseState.pop();
	}
}

private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
	RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
	advisorDefinition.setSource(parserContext.extractSource(advisorElement));

	// advice-ref,必须存在,不存在报错
	String adviceRef = advisorElement.getAttribute(ADVICE_REF);
	if (!StringUtils.hasText(adviceRef)) {
		parserContext.getReaderContext().error(
				"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
	}
	else {
		advisorDefinition.getPropertyValues().add(
				ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
	}

	// order
	if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
		advisorDefinition.getPropertyValues().add(
				ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
	}

	return advisorDefinition;
}


@Nullable
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
	// pointcut 和 pointcut-ref 只能存在一个
	if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
		parserContext.getReaderContext().error(
				"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
				element, this.parseState.snapshot());
		return null;
	}
	else if (element.hasAttribute(POINTCUT)) {
		// pointcut 直接创建一个 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition,此时 pointcut 配置的是切入点表达式
		String expression = element.getAttribute(POINTCUT);
		AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
		pointcutDefinition.setSource(parserContext.extractSource(element));
		return pointcutDefinition;
	}
	else if (element.hasAttribute(POINTCUT_REF)) {
		String pointcutRef = element.getAttribute(POINTCUT_REF);
		if (!StringUtils.hasText(pointcutRef)) {
			parserContext.getReaderContext().error(
					"'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
			return null;
		}
		return pointcutRef;
	}
	else {
		parserContext.getReaderContext().error(
				"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
				element, this.parseState.snapshot());
		return null;
	}
}

创建 beanClass 为 DefaultBeanFactoryPointcutAdvisor 的 BeanDefinition,之后解析 advice-ref、pointcut/pointcut-ref、order 等属性,设置 propertyValues,完成 BeanDefinition 的注册。

aspect

// ConfigBeanDefinitionParser
private void parseAspect(Element aspectElement, ParserContext parserContext) {
	// 获取 id 和 ref 属性
	String aspectId = aspectElement.getAttribute(ID);
	String aspectName = aspectElement.getAttribute(REF);

	try {
		this.parseState.push(new AspectEntry(aspectId, aspectName));
		List<BeanDefinition> beanDefinitions = new ArrayList<>();
		List<BeanReference> beanReferences = new ArrayList<>();

		// 处理子标签 declare-parents
		List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
		for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
			Element declareParentsElement = declareParents.get(i);
			beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
		}

		// We have to parse "advice" and all the advice kinds in one loop, to get the
		// ordering semantics right.
		NodeList nodeList = aspectElement.getChildNodes();
		boolean adviceFoundAlready = false;
		// 遍历子节点
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node node = nodeList.item(i);
			// 判断是否是通知节点,只有是通知节点才处理
			if (isAdviceNode(node, parserContext)) {
				// 依赖的切面类只处理一次
				if (!adviceFoundAlready) {
					adviceFoundAlready = true;
					// 必须存在切面类,不存在报错
					if (!StringUtils.hasText(aspectName)) {
						parserContext.getReaderContext().error(
								"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
								aspectElement, this.parseState.snapshot());
						return;
					}
					// 作为依赖的 bean 存在
					beanReferences.add(new RuntimeBeanReference(aspectName));
				}
				// 一个通知标签封装一个 Advisor,之后将这个 Advisor 对应的 BeanDefinition 注册到 BeanFactory
				AbstractBeanDefinition advisorDefinition = parseAdvice(
						aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
				beanDefinitions.add(advisorDefinition);
			}
		}

		AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
				aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
		parserContext.pushContainingComponent(aspectComponentDefinition);

		// aop:aspect 下 pointcut 子标签,作用和 aop:config 标签下 pointcut 子标签一致
		List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
		for (Element pointcutElement : pointcuts) {
			parsePointcut(pointcutElement, parserContext);
		}

		parserContext.popAndRegisterContainingComponent();
	}
	finally {
		this.parseState.pop();
	}
}

// 是 advice 节点,五种通知对应五个标签
private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
	if (!(aNode instanceof Element)) {
		return false;
	}
	else {
		String name = parserContext.getDelegate().getLocalName(aNode);
		return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
				AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
	}
}

private AbstractBeanDefinition parseAdvice(
		String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
		List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

	try {
		this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

		// create the method factory bean
		// method --> BeanDefinition
		RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
		methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
		methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
		methodDefinition.setSynthetic(true);

		// create instance factory definition
		// 切面实例工厂
		RootBeanDefinition aspectFactoryDef =
				new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
		aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
		aspectFactoryDef.setSynthetic(true);

		// register the pointcut
		// 封装通知 advice --> BeanDefinition
		AbstractBeanDefinition adviceDef = createAdviceDefinition(
				adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
				beanDefinitions, beanReferences);

		// configure the advisor
		// 配置 advisor,一个 advice 对应一个 advisor
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(adviceElement));
		advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
		// advisor order
		if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
		}

		// register the final advisor
		// 注册 advisor
		parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

		return advisorDefinition;
	}
	finally {
		this.parseState.pop();
	}
}
private AbstractBeanDefinition createAdviceDefinition(
		Element adviceElement, ParserContext parserContext, String aspectName, int order,
		RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
		List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

	// AspectJ 一种通知类型适配 spring 中一种通知类型
	RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
	adviceDefinition.setSource(parserContext.extractSource(adviceElement));

	// 添加属性
	adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
	adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);

	if (adviceElement.hasAttribute(RETURNING)) {
		adviceDefinition.getPropertyValues().add(
				RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
	}
	if (adviceElement.hasAttribute(THROWING)) {
		adviceDefinition.getPropertyValues().add(
				THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
	}
	if (adviceElement.hasAttribute(ARG_NAMES)) {
		adviceDefinition.getPropertyValues().add(
				ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
	}

	// 构造参数,每一个 AspectJXXXAdvice 构造方法都需要三个参数
	ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
	cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
	// 切点
	Object pointcut = parsePointcutProperty(adviceElement, parserContext);
	if (pointcut instanceof BeanDefinition) {
		cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
		beanDefinitions.add((BeanDefinition) pointcut);
	}
	else if (pointcut instanceof String) {
		RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
		cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
		beanReferences.add(pointcutRef);
	}
	// 切面实例工厂
	cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);

	return adviceDefinition;
}

private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
	String elementName = parserContext.getDelegate().getLocalName(adviceElement);
	if (BEFORE.equals(elementName)) {
		return AspectJMethodBeforeAdvice.class;
	}
	else if (AFTER.equals(elementName)) {
		return AspectJAfterAdvice.class;
	}
	else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
		return AspectJAfterReturningAdvice.class;
	}
	else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
		return AspectJAfterThrowingAdvice.class;
	}
	else if (AROUND.equals(elementName)) {
		return AspectJAroundAdvice.class;
	}
	else {
		throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
	}
}
// 前置通知
public AspectJMethodBeforeAdvice(
		Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

	super(aspectJBeforeAdviceMethod, pointcut, aif);
}

public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
	Assert.notNull(advice, "Advice must not be null");
	this.advice = advice;
	this.pointcut = advice.buildSafePointcut();
}

其实就是解析各种通知标签,之后封装 BeanDefinition,注册到 BeanFactory。一个通知对应一个 Advisor。

完成这些标签解析之后,也就在 BeanFactory 中注册了所有的 Advisor。

自动代理生成器的实例化

在 AbstractApplicationContext#refresh 中执行 registerBeanPostProcessors 时,完成 AspectJAwareAdvisorAutoProxyCreator 的实例化。

// AbstractAdvisorAutoProxyCreator
@Override
public void setBeanFactory(BeanFactory beanFactory) {
	// 父类 AbstractAutoProxyCreator
	super.setBeanFactory(beanFactory);
	if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
		throw new IllegalArgumentException(
				"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
	}
	initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 初始化赋值
	this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}

在初始化时,进行了相关字段的赋值。

AspectJAwareAdvisorAutoProxyCreator 继承 AbstractAutoProxyCreator,所以代理的生成也遵循 spring 中定义的逻辑。

至于前面解析的各种标签注册的 BeanDefinition,则在 AbstractApplicationContext#finishBeanFactoryInitialization 时完成实例对象的创建。

代理的实现

BeanFactory 中所有 Advisor 的实例化

在业务 bean 的实例化过程中,由于 AspectJAwareAdvisorAutoProxyCreator 的存在,就会执行到 AbstractAutoProxyCreator#postProcessBeforeInstantiation 方法中,判断业务 bean 是否需要代理。

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

	if (!StringUtils.hasLength(beanName) || !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.
	TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
	if (targetSource != null) {
		if (StringUtils.hasLength(beanName)) {
			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;
}

其中,AspectJAwareAdvisorAutoProxyCreator 重写了 shouldSkip 方法。

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
	// 获取所有候选 Advisor
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	// advisor 中 aspectName 如果和带创建的 beanName 一致,表明正在创建切面类实例,返回 true,表示切面类不需要代理
	for (Advisor advisor : candidateAdvisors) {
		if (advisor instanceof AspectJPointcutAdvisor &&
				((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
			return true;
		}
	}
	return super.shouldSkip(beanClass, beanName);
}

主要来看下 findCandidateAdvisors 这个方法。

// AbstractAdvisorAutoProxyCreator
protected List<Advisor> findCandidateAdvisors() {
	Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
	return this.advisorRetrievalHelper.findAdvisorBeans();
}

在 AspectJAwareAdvisorAutoProxyCreator 实例对象创建时,已经完成了 advisorRetrievalHelper 的创建赋值,是一个工具类 BeanFactoryAdvisorRetrievalHelper。

// BeanFactoryAdvisorRetrievalHelper
public List<Advisor> findAdvisorBeans() {
	// Determine list of advisor bean names, if not cached already.
	String[] advisorNames = this.cachedAdvisorBeanNames;
	if (advisorNames == null) {
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the auto-proxy creator apply to them!
		// 获取注册的所有 Advisor 对应的名称集合
		advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this.beanFactory, Advisor.class, true, false);
		this.cachedAdvisorBeanNames = advisorNames;
	}
	if (advisorNames.length == 0) {
		return new ArrayList<>();
	}

	List<Advisor> advisors = new ArrayList<>();
	for (String name : advisorNames) {
		if (isEligibleBean(name)) {
			if (this.beanFactory.isCurrentlyInCreation(name)) {
				if (logger.isTraceEnabled()) {
					logger.trace("Skipping currently created advisor '" + name + "'");
				}
			}
			else {
				try {
					// 对象未创建则在此时进行创建
					advisors.add(this.beanFactory.getBean(name, Advisor.class));
				}
				catch (BeanCreationException ex) {
					...
					// 抛出异常
				}
			}
		}
	}
	return advisors;
}

bean 的创建过程,此处不再赘述。有几点需要注意:

  1. 一个 pointcut 可以被多个 advisoraspect 下通知子标签引用,即可以在一个切入点应用多个顾问和通知,pointcut 对应的 beanClass 为 AspectJExpressionPointcut,创建 BeanDefinition 时设置 scope 为 prototype,所以每一个对 AspectJExpressionPointcut 的引用,都会创建一个新的对象。
  2. aspect 标签下各个通知子标签对应的 Advisor 为 AspectJPointcutAdvisor,持有的 Advice 为通知子标签封装的 AspectJXXXAdvice。
  3. AspectJPointcutAdvisor 构造方法注入时,需要 AbstractAspectJAdvice,而每一个 AspectJXXXAdvice 构造方法都需要三个参数,传递给父类 AbstractAspectJAdvice。
public AbstractAspectJAdvice(
		Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {

	Assert.notNull(aspectJAdviceMethod, "Advice method must not be null");
	this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
	this.methodName = aspectJAdviceMethod.getName();
	this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
	this.aspectJAdviceMethod = aspectJAdviceMethod;
	this.pointcut = pointcut;
	this.aspectInstanceFactory = aspectInstanceFactory;
}

第一个参数,需要的是一个切面类中的通知方法,在 aspect 标签解析时,针对通知标签,封装一个 beanClass 为 MethodLocatingFactoryBean 的 BeanDefinition。当解析第一个参数时,会执行 MethodLocatingFactoryBean 的创建。

// MethodLocatingFactoryBean
@Override
public void setBeanFactory(BeanFactory beanFactory) {
	if (!StringUtils.hasText(this.targetBeanName)) {
		throw new IllegalArgumentException("Property 'targetBeanName' is required");
	}
	if (!StringUtils.hasText(this.methodName)) {
		throw new IllegalArgumentException("Property 'methodName' is required");
	}

	Class<?> beanClass = beanFactory.getType(this.targetBeanName);
	if (beanClass == null) {
		throw new IllegalArgumentException("Can't determine type of bean with name '" + this.targetBeanName + "'");
	}
	this.method = BeanUtils.resolveSignature(this.methodName, beanClass);

	if (this.method == null) {
		throw new IllegalArgumentException("Unable to locate method [" + this.methodName +
				"] on bean [" + this.targetBeanName + "]");
	}
}

会在 MethodLocatingFactoryBean 对象初始化时,完成目标通知方法的确定。

// BeanUtils 根据方法名称从指定 clazz 中确定 method
@Nullable
public static Method resolveSignature(String signature, Class<?> clazz) {
	Assert.hasText(signature, "'signature' must not be empty");
	Assert.notNull(clazz, "Class must not be null");
	int startParen = signature.indexOf('(');
	int endParen = signature.indexOf(')');
	if (startParen > -1 && endParen == -1) {
		throw new IllegalArgumentException("Invalid method signature '" + signature +
				"': expected closing ')' for args list");
	}
	else if (startParen == -1 && endParen > -1) {
		throw new IllegalArgumentException("Invalid method signature '" + signature +
				"': expected opening '(' for args list");
	}
	else if (startParen == -1) {
		// 不指定参数类型
		return findMethodWithMinimalParameters(clazz, signature);
	}
	else {
		// 方法名
		String methodName = signature.substring(0, startParen);
		// 逗号分割,获取参数类型数组
		String[] parameterTypeNames =
				StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));
		Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
		for (int i = 0; i < parameterTypeNames.length; i++) {
			String parameterTypeName = parameterTypeNames[i].trim();
			try {
				// 加载类型,保证配置的每一个类型的正确性
				parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" +
						parameterTypeName + "] for argument " + i + ". Root cause: " + ex);
			}
		}
		// 根据类型获取指定方法
		return findMethod(clazz, methodName, parameterTypes);
	}
}

@Nullable
public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName)
		throws IllegalArgumentException {

	// 实际上 clazz.getMethods() 已经包含了当前类及所有父类中 public、protected 修饰的方法,但不包含 private 方法
	Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);
	if (targetMethod == null) {
		// 当目标方法为 private 修饰时,通过以下方法查找
		targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);
	}
	return targetMethod;
}
@Nullable
public static Method findMethodWithMinimalParameters(Method[] methods, String methodName)
		throws IllegalArgumentException {

	Method targetMethod = null;
	int numMethodsFoundWithCurrentMinimumArgs = 0;
	for (Method method : methods) {
		// 比较参数名称
		if (method.getName().equals(methodName)) {
			int numParams = method.getParameterCount();
			// 将参数长度最短的方法作为 targetMethod 返回
			if (targetMethod == null || numParams < targetMethod.getParameterCount()) {
				targetMethod = method;
				numMethodsFoundWithCurrentMinimumArgs = 1;
			}
			else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
				// 用常规方法覆盖桥接方法
				if (targetMethod.isBridge()) {
					// Prefer regular method over bridge...
					targetMethod = method;
				}
				else {
					// Additional candidate with same length
					// 当存在方法重写或重载时,发现了两个名称和参数长度一样的方法,数量自增
					numMethodsFoundWithCurrentMinimumArgs++;
				}
			}
		}
	}
	// 存在方法重写时抛出异常,即不确定使用的是子类方法还是父类方法
    // 重载时也会存在,方法名称一致,参数长度一致,但类型不一致,此处只校验长度,无法确定是哪一个方法
	if (numMethodsFoundWithCurrentMinimumArgs > 1) {
		throw new IllegalArgumentException("Cannot resolve method '" + methodName +
				"' to a unique method. Attempted to resolve to overloaded method with " +
				"the least number of parameters but there were " +
				numMethodsFoundWithCurrentMinimumArgs + " candidates.");
	}
	return targetMethod;
}

// 查找当前类,并递归父类,返回 public、protected、private 修饰方法
@Nullable
public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName)
		throws IllegalArgumentException {

	Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
	if (targetMethod == null && clazz.getSuperclass() != null) {
		targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);
	}
	return targetMethod;
}

@Nullable
public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
	try {
		return clazz.getMethod(methodName, paramTypes);
	}
	catch (NoSuchMethodException ex) {
		return findDeclaredMethod(clazz, methodName, paramTypes);
	}
}

上面的代码解释了在切面类中确定目标通知方法的实现,主要逻辑如下:

  1. 不指定方法参数类型时,按最短参数长度查找,指定参数类型时,按参数类型查找,也就是说,xml 中配置 methodName 时,可以是 methodName(argType1,argType2) 这种配置原型。
  2. 不指定方法参数类型时,按最短参数长度查找,若存在方法重写和方法重载导致的多个方法名称和参数长度一致,会抛出异常
  3. private 修饰的方法也可以被找到而作为目标通知方法

MethodLocatingFactoryBean 创建完成之后,由于是 FactoryBean 子类,会调用 this.beanFactory.getObjectFromFactoryBean 获取真正的对象。

// MethodLocatingFactoryBean
@Override
@Nullable
public Method getObject() throws Exception {
	return this.method;
}

 可以看到,获取的 Method 对象就是上面在切面类中确定的方法。这也解释了为什么 AspectJXXXAdvice 构造方法第一个参数类型为 Method,而解析标签时却配置了一个 MethodLocatingFactoryBean 工厂。

接下来看第二个构造参数,需要的是一个 AspectJExpressionPointcut,通知子标签支持 pointcut 和 pointcut-ref 两种方式来定义切入点。

解析标签时,如果是 pointcut,直接创建一个 beanClass 为 AspectJExpressionPointcut 的 BeanDefinition,此时 pointcut 配置的是切入点表达式字符串;如果是 pointcut-ref,表明是一个引用类型,引用的 aop:pointcut 子标签已经封装成了 BeanDefinition,此处返回名称字符串封装一个 RuntimeBeanReference。所以传递给第二个构造参数的,要么是一个 BeanDefinition,要么是一个 RuntimeBeanReference。

在 ConstructorResolver#resolveConstructorArguments 方法中,解析构造参数,不管是 BeanDefinition,还是 RuntimeBeanReference 引用,由于背后定义 BeanDefinition 时设置的 scope 都是 prototype,所以此处都会创建一个新的对象。

第三个参数,需要一个 AspectInstanceFactory,即切面实例工厂,传入的是一个 beanClass 为 SimpleBeanFactoryAwareAspectInstanceFactory 的 BeanDefinition,而这个 SimpleBeanFactoryAwareAspectInstanceFactory 就是 AspectInstanceFactory 的实现类,在此时完成实例化对象创建。

事实上,aspect 下的通知子标签,一个通知对应一个 Advisor,即 AspectJPointcutAdvisor,由于存在构造参数,采用构造方法实例化,此时又对依赖的构造参数 AbstractAspectJAdvice 进行了实例化创建,这个 AbstractAspectJAdvice 又存在构造参数,继续采用 AbstractAutowireCapableBeanFactory#autowireConstructor 进行实例化对象创建。

创建完 AspectJXXXAdvice,将其作为构造参数,完成 AspectJPointcutAdvisor 的实例化。

public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
	Assert.notNull(advice, "Advice must not be null");
	this.advice = advice;
	this.pointcut = advice.buildSafePointcut();
}

在构造方法中执行了 advice.buildSafePointcut(),这是在做什么呢?继续向下看。

// AbstractAspectJAdvice
public final Pointcut buildSafePointcut() {
	// AspectJExpressionPointcut
	Pointcut pc = getPointcut();
	MethodMatcher safeMethodMatcher = MethodMatchers.intersection(
			new AdviceExcludingMethodMatcher(this.aspectJAdviceMethod), pc.getMethodMatcher());
	// 组合
	return new ComposablePointcut(pc.getClassFilter(), safeMethodMatcher);
}

// AspectJExpressionPointcut
@Override
public MethodMatcher getMethodMatcher() {
	obtainPointcutExpression();
	return this;
}

// AspectJExpressionPointcut
private PointcutExpression obtainPointcutExpression() {
	if (getExpression() == null) {
		throw new IllegalStateException("Must set property 'expression' before attempting to match");
	}
	if (this.pointcutExpression == null) {
		this.pointcutClassLoader = determinePointcutClassLoader();
		// 解析切入点表达式,创建 PointcutExpressionImpl 返回
		this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
	}
	return this.pointcutExpression;
}

public static MethodMatcher intersection(MethodMatcher mm1, MethodMatcher mm2) {
	return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ?
			new IntersectionIntroductionAwareMethodMatcher(mm1, mm2) : new IntersectionMethodMatcher(mm1, mm2));
}

public IntersectionIntroductionAwareMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
	super(mm1, mm2);
}

pc.getMethodMatcher() 时完成了 pc 中切入点表达式的解析,创建了一个 org.aspectj.internal.lang.reflect.PointcutExpressionImpl 对象赋值给 AspectJExpressionPointcut 中的 pointcutExpression 字段。之后创建一个 IntersectionIntroductionAwareMethodMatcher 对象作为 safeMethodMatcher,之后将 safeMethodMatcher 和 pc.getClassFilter() 返回的 AspectJExpressionPointcut 组合起来,封装一个 ComposablePointcut 返回。

完成 AspectJPointcutAdvisor 的对象创建之后,将其加入 advisors 集合,之后将集合返回,作为候选的 Advisor,即 candidateAdvisors。

再回到 AspectJAwareAdvisorAutoProxyCreator#shouldSkip 方法中,遍历 candidateAdvisors,advisor 中 aspectName 如果和当前创建的 beanName 一致,表明正在创建切面类实例,返回 true,即需要跳过。之后在 AbstractAutoProxyCreator#postProcessBeforeInstantiation 中,针对当前 beanClass 和 beanName 生成的 cacheKey,标记为 false。

代理对象的创建

完成目标类的实例化之后,在进行初始化时,由于 AspectJAwareAdvisorAutoProxyCreator 的存在,会执行到 AbstractAutoProxyCreator#postProcessAfterInitialization --> wrapIfNecessary。

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

这是 spring 创建代理的模板。先来看对 Advisor 的过滤,找到当前目标类需要的 Advisor。

// AbstractAdvisorAutoProxyCreator
@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();
}
// AbstractAdvisorAutoProxyCreator
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	// 获取所有 BeanFaactory 中定义的 Advisor,前面创建过,所以此处获取很快
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	// 筛选
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	// 扩展
	extendAdvisors(eligibleAdvisors);
	// 排序
	if (!eligibleAdvisors.isEmpty()) {
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

// AopUtils
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;
		}
		if (canApply(candidate, clazz, hasIntroductions)) {
			eligibleAdvisors.add(candidate);
		}
	}
	return eligibleAdvisors;
}
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) {
		// 对于 Advisor 为 DefaultBeanFactoryPointcutAdvisor,在进行 canApply 时执行 pc.getClassFilter 完成切入点表达式的解析
		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();
	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) {
			if (introductionAwareMethodMatcher != null ?
					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}

	return false;
}

这些都是 spring 中实现 AOP 的通用代码,区别就在于不同的 org.springframework.aop.PointcutAdvisor,持有的 org.springframework.aop.Pointcut 不同,不同的 org.springframework.aop.Pointcut,持有的 ClassFilter 和 MethodMatcher 不同。实现AopUtils#canApply 时,利用每个 org.springframework.aop.Pointcut 中 ClassFilter 和 MethodMatcher 中定义的 matches 方法进行匹配。所以也可以按照自己定义的规则,对 org.springframework.aop.Pointcut 进行扩展。

找到合格的 Advisor 之后,调用 AbstractAdvisorAutoProxyCreator#extendAdvisors,而 AspectJAwareAdvisorAutoProxyCreator 对此方法进行了重写。

@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
	AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
	// Don't add advisors to an empty list; may indicate that proxying is just not required
	if (!advisors.isEmpty()) {
		boolean foundAspectJAdvice = false;
		for (Advisor advisor : advisors) {
			// Be careful not to get the Advice without a guard, as this might eagerly
			// instantiate a non-singleton AspectJ aspect...
			if (isAspectJAdvice(advisor)) {
				foundAspectJAdvice = true;
				break;
			}
		}
		if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
			advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
			return true;
		}
	}
	return false;
}
private static boolean isAspectJAdvice(Advisor advisor) {
	return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
			advisor.getAdvice() instanceof AbstractAspectJAdvice ||
			(advisor instanceof PointcutAdvisor &&
					((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}

判定是否 Advisor 集合中存在 AspectJAdvice,存在,在 Advisor 集合的首位加入 ExposeInvocationInterceptor.ADVISOR。至于为啥要加入这个 Advisor,可以参考 spring 中 AspectJ 基于注解的实现分析。

此处有一点要注意,就是如果 Advisor 为 DefaultBeanFactoryPointcutAdvisor,此前虽然进行了实例化,但其中依赖的 Advice 并未进行实例化,此时执行 advisor.getAdvice() 会对依赖的 Advice 完成实例化。

扩展完 eligibleAdvisors 之后,对 eligibleAdvisors 按照优先级进行排序。详细的排序过程可以参考AspectJ 下 Advisor 的排序过程。

排序之后,将集合处理成数组返回,赋值给 specificInterceptors。

之后调用 AbstractAutoProxyCreator#createProxy 创建代理,此时 AbstractAutoProxyCreator 就是 AspectJAwareAdvisorAutoProxyCreator,将 <aop:config> 标签中定义的 proxy-target-class 和 expose-proxy 两个属性又传递给 ProxyFactory。

// AbstractAutoProxyCreator
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
		@Nullable Object[] specificInterceptors, TargetSource targetSource) {

	if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
		AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
	}

	ProxyFactory proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);

	if (proxyFactory.isProxyTargetClass()) {
		// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
		if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
			// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
			for (Class<?> ifc : beanClass.getInterfaces()) {
				proxyFactory.addInterface(ifc);
			}
		}
	}
	else {
		// No proxyTargetClass flag enforced, let's apply our default checks...
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	// true
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	// Use original ClassLoader if bean class not locally loaded in overriding class loader
	ClassLoader classLoader = getProxyClassLoader();
	if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
		classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
	}
	return proxyFactory.getProxy(classLoader);
}

创建代理的这一步,都是遵循 spring 中的定义来实现。

方法调用

相同处理的,此处不在赘述,可以参考spring 中自动代理生成器的实现。

有一点需要注意,就是调用 DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法时,遍历 advisors。前面介绍过,aspect 标签下通知对应的 Advisor 为 AspectJPointcutAdvisor,在执行有参构造时,封装的 pointcut 为 ComposablePointcut。

两个字段,主要关注 methodMatcher,通过前面的介绍,这个 methodMatcher 为 MethodMatchers$IntersectionIntroductionAwareMethodMatcher。 mm1 为定义的 AbstractAspectJAdvice$AdviceExcludingMethodMatcher,mm2 为 pc.getMethodMatcher(),也就是 Pointcut 中持有的 MethodMatcher。

此时调用 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); 得到 MethodMatchers$IntersectionIntroductionAwareMethodMatcher,接着调用其 matches 方法。

// IntersectionIntroductionAwareMethodMatcher
@Override
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
	return (MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
			MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
}
// MethodMatches
public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(mm, "MethodMatcher must not be null");
	return (mm instanceof IntroductionAwareMethodMatcher ?
			((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions) :
			mm.matches(method, targetClass));
}
// AdviceExcludingMethodMatcher
@Override
public boolean matches(Method method, Class<?> targetClass) {
	return !this.adviceMethod.equals(method);
}

AdviceExcludingMethodMatcher 并不是 IntroductionAwareMethodMatcher 实例,调用 AdviceExcludingMethodMatcher#matches 方法判定目标方法是否是通知方法,不是返回 true。所以主要的判断还是基于 mm2,mm2 为 AspectJExpressionPointcut。

// AspectJExpressionPointcut
@Override
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
	obtainPointcutExpression();
	// org.aspectj.weaver.tools.ShadowMatch
	ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);

	// Special handling for this, target, @this, @target, @annotation
	// in Spring - we can optimize since we know we have exactly this class,
	// and there will never be matching subclass at runtime.
	if (shadowMatch.alwaysMatches()) {
		return true;
	}
	else if (shadowMatch.neverMatches()) {
		return false;
	}
	else {
		// the maybe case
		if (hasIntroductions) {
			return true;
		}
		// A match test returned maybe - if there are any subtype sensitive variables
		// involved in the test (this, target, at_this, at_target, at_annotation) then
		// we say this is not a match as in Spring there will never be a different
		// runtime subtype.
		RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
		return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
	}
}

进入 AspectJExpressionPointcut#matches,委托给 AspectJ 进行切入点表达式和目标方法的匹配。

之后将筛选出的 Advisor,根据持有的通知类型的不同,适配成不同的 org.aopalliance.intercept.MethodInterceptor,封装成拦截器链。接着封装 MethodInvocation,调用 proceed 方法。

总结

介绍完了 AspectJ 下基于注解和 XML 的 AOP实现。现在我们来总结一下这两者的区别。

标签解析

实现方式标签解析器
注解AspectJAutoProxyBeanDefinitionParser
XMLConfigBeanDefinitionParser

代理生成器

实现方式代理生成器
注解AnnotationAwareAspectJAutoProxyCreator
XMLAspectJAwareAdvisorAutoProxyCreator

Advisor 的创建

实现方式代理生成器
注解AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
XMLAbstractAdvisorAutoProxyCreator#findCandidateAdvisors

注解方式下,AnnotationAwareAspectJAutoProxyCreator 重写了 findCandidateAdvisors 方法,通过找到持有 @Aspect 注解的类,接着获取类中定义的通知方法,将其封装成 Advisor。

而 XML 模式下,由于在 XML 中已经定义了切面类、切入点、通知和顾问,所以会采用 spring 中定义的通用模板来获取 Advisor。

Advisor 的类型

实现方式Advisor 类型
注解InstantiationModelAwarePointcutAdvisorImpl
XMLadvisor 标签对应 DefaultBeanFactoryPointcutAdvisor
aspect 下通知子标签对应 AspectJPointcutAdvisor

除了这些显式的不同,还有一个隐式的不同点,就是 AspectJ 解析 expression 的时机

实现方式Advisor 类型AspectJ 解析 expression 的时机
注解InstantiationModelAwarePointcutAdvisorImplAbstractAdvisorAutoProxyCreator下findEligibleAdvisors 方法中对获取的 candidateAdvisors 进行筛选时完成
XMLDefaultBeanFactoryPointcutAdvisor
AspectJPointcutAdvisor有参构造方法实例化,执行 buildSafePointcut 方法时完成

下面我们来看下注解和 XML 这两种实现方式的共同点。

Advisor 的创建时机,都是在执行 AbstractAutoProxyCreator#postProcessBeforeInstantiation ,第一次调用 shouldSkip 方法时完成的,并将创建的 Advisor 实例对象加入到了 DefaultListableBeanFactory 的父类 DefaultSingletonBeanRegistry 中的 singletonObjects,之后获取 Advisor 时直接从 singletonObjects 获取。

业务 bean 代理对象的创建和方法调用,完全遵从 spring 中定义的 AOP 实现。至于方法匹配,则通过 AspectJExpressionPointcut 这个纽带,完全委托给了 AspectJ 这个框架去实现。


http://www.kler.cn/a/546794.html

相关文章:

  • 安全启动(secure boot)怎么关闭_史上最全的各品牌机和组装机关闭安全启动教程
  • 将错误消息输出到标准错误流:Rust中的最佳实践
  • web第三次作业
  • 浏览器安全学习
  • 中兴R5300 G4服务器配置磁盘RAID
  • 人工智能之知识图谱实战系列
  • 三格电子——TCP转ProfibusDP网关使用场景
  • 从技术债务到架构升级,滴滴国际化外卖的变革
  • [0696].第11节:Kafka-Eagle监控
  • dayjs的isSameOrAfter、isSameOrBefore、isAfter、isBefore学习
  • 微软AutoGen高级功能——Selector Group Chat
  • 【webview Android】视频获取首帧为封面
  • 服务器防护(ubuntu)
  • 辛格迪客户案例 | 钥准医药科技GMP文件管理(DMS)项目
  • oracle 19c安装DBRU补丁时报错CheckSystemSpace的处理
  • 百度 AI开源!将在6月30日开源文心大模型4.5系列
  • 上下文编辑器在不同场景下的功能(含使用案例)
  • Spring Boot 常用依赖详解:如何选择和使用常用依赖
  • django上传文件
  • grep如何排除多个目录?