文档章节

Spring源码-AOP(七)-整合AspectJ

青离
 青离
发布于 2017/09/05 20:15
字数 3457
阅读 1313
收藏 48

Spring AOP 源码解析系列,建议大家按顺序阅读,欢迎讨论

  1. Spring源码-AOP(一)-代理模式
  2. Spring源码-AOP(二)-AOP概念
  3. Spring源码-AOP(三)-Spring AOP的四种实现
  4. Spring源码-AOP(四)-ProxyFactory
  5. Spring源码-AOP(五)-ProxyFactoryBean
  6. Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator
  7. Spring源码-AOP(七)-整合AspectJ

Spring AOP的实现已经臻于非常完善,而通过与AspectJ的整合使得AOP的使用简单且灵活。不论是XML还是注解,都实现了非侵入式的控制。而基于自动代理的基础上,整合的AspectJ也通过BeanPostProcessor扩展的方式实现细粒度的切面控制。XML方式通过以aop:config标签实现配置,注解方式则通过@Aspect声明切面类。两种方式底层的实现殊途同归,都是基于自动代理的基类AbstractAutoProxyCreator来完成。

Spring的组件通过XML配置进行注册以及初始化,其方式就是实现特定命名空间的NamespaceHandler接口,对于Spring+AspectJ的整合方式的XML配置,是从AopNamespaceHandler开始。其中注册了两个标签,config和aspectj-autoproxy,分别为XML配置的根标签,和注解方式的启用配置。

registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

不同的解析器对应的处理最终实现了XML或注解方式的AspectJ AOP。

1.XML配置

先看一个XML配置的demo

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
	
	<!-- 原始对象 -->
	<bean id="chromeBrowser" class="com.lcifn.spring.aop.bean.ChromeBrowser"/>
	<!-- 环绕增强对象 -->
	<bean id="aspectjBrowserAroundAdvice" class="com.lcifn.spring.aop.advice.AspectJBrowserAroundAdvice"></bean>
	
	<!-- aspectj aop 配置 -->
	<aop:config proxy-target-class="true">
		<aop:pointcut id="browserPointcut" expression="execution(* com.lcifn.spring.aop.bean.*.*(..))"/>
		<aop:aspect ref="aspectjBrowserAroundAdvice">
			<aop:around method="aroundIntercept" pointcut-ref="browserPointcut"/>
		</aop:aspect>
	</aop:config>
</beans>

ConfigBeanDefinitionParser解析器用来处理XML配置,Spring的代码大多使用命名清晰的子方法来描述主结构。

ConfigBeanDefinitionParser.java

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

	// 配置自动代理创建,基于AbstractAutoProxyCreator实现切面的发现和匹配
	configureAutoProxyCreator(parserContext, element);

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

	parserContext.popAndRegisterContainingComponent();
	return null;
}

parse方法的主要内容分为两部分,自动代理配置的创建以及代理XML配置的解析,可以从上面代码中很清晰的看出。

自动代理配置的创建

自动代理配置是基类AbstractAutoProxyCreator的子类AspectJAwareAdvisorAutoProxyCreator,来实现AspectJ相关的AOP的实现。其主要的类结构如下:

  • AbstractAutoProxyCreator:基于BeanPostProcessor扩展完成AOP代理的创建
  • AbstractAdvisorAutoProxyCreator:切面的发现和匹配
  • AspectJAwareAdvisorAutoProxyCreator:AspectJ相关支持

而configureAutoProxyCreator方法则完成了自动代理配置的初始化。

private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
	AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}

由工具类AopNamespaceUtils实现

AopNamespaceUtils.java

public static void registerAspectJAutoProxyCreatorIfNecessary(
		ParserContext parserContext, Element sourceElement) {
	// 注册AspectJ自动代理创建类
	BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
			parserContext.getRegistry(), parserContext.extractSource(sourceElement));
	// 设置proxyTargetClass和exposeProxy属性
	useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
	registerComponentIfNecessary(beanDefinition, parserContext);
}

对于AspectJ自动代理创建类的注册有一个优先级机制,即当前容器中已存在自动代理创建类的bean,则以优先级高的替换优先级低的。

AopConfigUtils.java

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
	return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	// 存在同名的AUTO_PROXY_CREATOR
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			// 传入的优先级高于原有的,则替换BeanDefinition的className
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}
	// 不存在同名,则创建新的BeanDefinition
	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}

对于自动代理创建类的优先级,在Spring中定义了三个

// 基础版
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
// XML配置	
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
// 注解配置
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);

因而同时存在XML和注解时,注解的自动代理创建类会覆盖XML的。但AnnotationAwareAspectJAutoProxyCreator其实是AspectJAwareAdvisorAutoProxyCreator的子类,在查询候选Advisor时,会先调用父类的方法获取XML配置中的Advisor。

另外aop:config可以配置proxy-target-class和expose-proxy,通过useClassProxyingIfNecessary方法设置到AspectJAwareAdvisorAutoProxyCreator的BeanDefinition的属性中。

AopNamespaceUtils.java

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
	if (sourceElement != null) {
		boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
		if (proxyTargetClass) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
		if (exposeProxy) {
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}
}

代理XML配置的解析

注册完自动代理创建类,接下来就是aop的具体配置。常用的一般是aop:pointcutaop:aspect两个标签,aop:advisor通常在外部aop:config外存在advice配置时使用。

对pointcut的解析比较简单,就是获取id及expression属性,然后创建pointcut的BeanDefinition。

ConfigBeanDefinitionParser.java

private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
	String id = pointcutElement.getAttribute(ID);
	String expression = pointcutElement.getAttribute(EXPRESSION);

	AbstractBeanDefinition pointcutDefinition = null;

	try {
		this.parseState.push(new PointcutEntry(id));
		pointcutDefinition = createPointcutDefinition(expression);
		pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

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

主要来看下对aspect的解析,在aop:aspect中的有两类子标签,一种是pointcut切入点的配置,一种是advice增强的配置,而advice又分为前置增强,后置增强,环绕增强等。

ConfigBeanDefinitionParser.java	

private void parseAspect(Element aspectElement, ParserContext parserContext) {
	String aspectId = aspectElement.getAttribute(ID);
	String aspectName = aspectElement.getAttribute(REF);

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

		// 解析引入增强
		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;
					}
					beanReferences.add(new RuntimeBeanReference(aspectName));
				}
				// 解析advice增强,组装BeanDefinition
				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);

		// 解析pointcut标签
		List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
		for (Element pointcutElement : pointcuts) {
			parsePointcut(pointcutElement, parserContext);
		}

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

对advice增强的解析parseAdvice方法是核心部分,而其返回的是组装好的Advisor切面BeanDefinition

ConfigBeanDefinitionParser.java	

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对象的工厂bean
		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
		// 用来获取切面类对象的工厂bean
		RootBeanDefinition aspectFactoryDef =
				new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
		aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
		aspectFactoryDef.setSynthetic(true);

		// register the pointcut
		// 根据不同的增强标签创建不同的增强BeanDefinition
		AbstractBeanDefinition adviceDef = createAdviceDefinition(
				adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
				beanDefinitions, beanReferences);

		// configure the advisor
		// 创建AspectJPointcutAdvisor,封装上面创建的AdviceBeanDefinition
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(adviceElement));
		advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
		if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
		}

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

		return advisorDefinition;
	}
	finally {
		this.parseState.pop();
	}
}

此方法中先创建了两个合成的BeanDefinition,一个为增强方法的工厂,一个为切面对象的工厂,用来最终通过反射调用时使用。而后根据不同的advice标签(aop:before,aop:after-returning等)创建相应的增强BeanDefinition,最后使用AspectJPointcutAdvisor封装增强BeanDefinition然后返回。

再来看看对advice标签的解析createAdviceDefinition方法

private AbstractBeanDefinition createAdviceDefinition(
		Element adviceElement, ParserContext parserContext, String aspectName, int order,
		RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
		List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

	// 创建advice的BeanDefinition,获取advice对应的Class对象
	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);

	// after-returning的returning属性解析
	if (adviceElement.hasAttribute(RETURNING)) {
		adviceDefinition.getPropertyValues().add(
				RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
	}
	// after-throwing的throwing属性解析
	if (adviceElement.hasAttribute(THROWING)) {
		adviceDefinition.getPropertyValues().add(
				THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
	}
	// arg-names参数昵称属性解析
	if (adviceElement.hasAttribute(ARG_NAMES)) {
		adviceDefinition.getPropertyValues().add(
				ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
	}

	// 创建AdviceBeanDefinition构造函数
	ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
	// 构造函数设置增强方法工厂
	cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);

	// 构造函数设置pointcut
	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;
}

不同的Advice标签对应不同的Advice类,但都继承同一个基类AbstractAspectJAdvice。AbstractAspectJAdvice定义了构造函数

public AbstractAspectJAdvice(
	Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
}

创建Advice的BeanDefinition时,即按照此构造函数组装BeanDefinition中的ConstructorArgumentValues属性。

而对于不同的advice则通过getAdviceClass方法匹配对应的Class

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 + "].");
	}
}

至此,每个Advice都设置了切入点,切面类以及增强方法,再由AspectJPointcutAdvisor对Advice进行封装,在每个bean初始化之后,AspectJAwareAdvisorAutoProxyCreator的基类AbstractAutoProxyCreator实现了BeanPostProcessor扩展,查询所有的匹配bean的Advisor,并创建bean对应的Proxy代理,在方法真正执行时,触发其相应的Advice执行。

2.注解配置

不论是通过<aop:aspectj-autoproxy/>还是@EnableAspectJAutoProxy配置的AspectJ注解支持,都是通过AnnotationAwareAspectJAutoProxyCreator支撑对AspectJ相关注解的解析和注册。AnnotationAwareAspectJAutoProxyCreator继承AnnotationAwareAspectJAutoProxyCreator,并覆盖了查询所有候选Advisor的方法findCandidateAdvisors。基于此方法对@Aspect的切面类进行解析,并生成相应Advisor对象返回。

AnnotationAwareAspectJAutoProxyCreator.java

protected List<Advisor> findCandidateAdvisors() {
	// Add all the Spring advisors found according to superclass rules.
	// 调用父类方法,兼容XML和注解并存
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	// 解析注解方式的切面
	advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	return advisors;
}

核心操作交由BeanFactoryAspectJAdvisorsBuilder类的buildAspectJAdvisors方法实现

BeanFactoryAspectJAdvisorsBuilder.java

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

	synchronized (this) {
		// 缓存aspectName
		aspectNames = this.aspectBeanNames;
		if (aspectNames == null) {
			List<Advisor> advisors = new LinkedList<Advisor>();
			aspectNames = new LinkedList<String>();
			// 获取所有spring容器中的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
				Class<?> beanType = this.beanFactory.getType(beanName);
				if (beanType == null) {
					continue;
				}
				// 有@Aspect注解
				if (this.advisorFactory.isAspect(beanType)) {
					aspectNames.add(beanName);
					AspectMetadata amd = new AspectMetadata(beanType, beanName);
					if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
						// 创建Aspect实例工厂
						MetadataAwareAspectInstanceFactory factory =
								new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
						// 根据Aspect实例工厂获取所有Advisor对象
						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>();
	// 如果aspectNames不为空,则从缓存中获取对应的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;
}

核心方法是根据Aspect实例工厂获取所有Advisor对象

ReflectiveAspectJAdvisorFactory.java

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
	final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
	final String aspectName = maaif.getAspectMetadata().getAspectName();
	validate(aspectClass);

	// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
	// so that it will only instantiate once.
	// 懒加载装饰类封装Aspect实例工厂
	final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
			new LazySingletonAspectInstanceFactoryDecorator(maaif);

	final List<Advisor> advisors = new LinkedList<Advisor>();
	for (Method method : getAdvisorMethods(aspectClass)) {
		// 返回有Advice类型(@Before,@AfterReturning等)的注解方法生成的Advisor
		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链最前增加一个前置拦截器,用来初始化切面类
		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方法执行具体的操作

ReflectiveAspectJAdvisorFactory.java

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

	validate(aif.getAspectMetadata().getAspectClass());

	// 获取pointcut切入点expression表达式对象
	AspectJExpressionPointcut ajexp =
			getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
	if (ajexp == null) {
		return null;
	}
	// 实例化Advisor对象,支持懒加载策略
	return new InstantiationModelAwarePointcutAdvisorImpl(
			this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
}

Advisor对应的Advice对象的实例化实际发生在InstantiationModelAwarePointcutAdvisorImpl的构造方法中

public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
		MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {

	this.declaredPointcut = ajexp;
	this.method = method;
	this.atAspectJAdvisorFactory = af;
	this.aspectInstanceFactory = aif;
	this.declarationOrder = declarationOrderInAspect;
	this.aspectName = aspectName;

	if (aif.getAspectMetadata().isLazilyInstantiated()) {
		// Static part of the pointcut is a lazy type.
		Pointcut preInstantiationPointcut =
				Pointcuts.union(aif.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, aif);
		this.lazy = true;
	}
	else {
		// A singleton aspect.
		// 实例化Advice
		this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		this.pointcut = declaredPointcut;
		this.lazy = false;
	}
}

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

通过ReflectiveAspectJAdvisorFactory工厂类完成

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
		MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {

	Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
	validate(candidateAspectClass);

	// 获取方法上的AspectJ注解
	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;

	// 根据不同AspectJ注解生成对应的Advice对象
	switch (aspectJAnnotation.getAnnotationType()) {
		case AtBefore:
			springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
			break;
		case AtAfter:
			springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
			break;
		case AtAfterReturning:
			springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
			springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		case AtAround:
			springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
			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...
	// 配置Advice对象
	springAdvice.setAspectName(aspectName);
	springAdvice.setDeclarationOrder(declarationOrderInAspect);
	String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
	if (argNames != null) {
		springAdvice.setArgumentNamesFromStringArray(argNames);
	}
	springAdvice.calculateArgumentBindings();
	return springAdvice;
}

至此,注解方式的切面类中的每个Advice方法生成对应的Advice对象,并被InstantiationModelAwarePointcutAdvisor实现类封装然后返回。

相比于XML配置的方式,注解方式的Advisor不会生成BeanDefinition注册到Spring容器中,而是直接返回到Advisor集合中,并以aspectName的方式进行缓存防止重复生成及性能优化。

对于Spring+AspectJ的方式,其主要操作都在于Advisor的解析和生产,底层通过Spring自动代理的方式被Spring容器初始化bean时调用。而AOP代理则是使用ProxyFactory,根据不同配置决定JDK或CGLIB的方式来生成。

Spring AOP的四种实现中四种方式,其实也是Sping AOP的演进的过程,而对这四种方式源码的解析,也证明了高级特性都是基于基础功能实现的。希望借由这四种方式的源码解析,能够对Spring AOP的原理能够有深入的理解,期待大家的交流!

© 著作权归作者所有

青离
粉丝 300
博文 51
码字总数 114378
作品 0
海淀
后端工程师
私信 提问
加载中

评论(1)

李嘉图
李嘉图
不错,学习了
2014-03-11 Spring的学习(3)------面向切面编程(AOP)

AOP概念 首先让我们从一些重要的AOP概念和术语开始。这些术语不是Spring特有的。不过AOP术语并不是特别的直观,如果Spring使用自己的术语,将会变得更加令人困惑。 切面(Aspect):一个关注...

查封炉台
2014/03/11
395
0
Aspectj与Spring AOP比较

1、简介 今天有多个可用的 AOP 库, 它们需要能够回答许多问题: 是否与用户现有的或新的应用程序兼容? 在哪里可以实现 AOP? 与自己的应用程序集成多快? 性能开销是多少? 在本文中, 我们将...

沈渊
2018/04/18
0
0
spring aop 如何切面到mvc 的controller

网上搜罗半天,不知道什么原因,看了源码,好像他们说的controller 是不受代理的,也对哈,不知道怎么办,于是在http://stackoverflow.com/questions/17834958/spring-aop-is-not-working-i...

_白开水_
2013/10/06
5.3K
0
实例简述Spring AOP之对AspectJ语法的支持

Spring的AOP可以通过对@AspectJ注解的支持和在XML中配置来实现,本文通过实例简述如何在Spring中使用AspectJ. 一:使用AspectJ注解: 1,启用对AspectJ的支持: 通过在Spring的配置中引入下列元素...

晨曦之光
2012/04/25
893
0
《Spring Recipes》第三章笔记1:Enabling AspectJ Annotation

《Spring Recipes》第三章笔记:Enabling AspectJ Annotation 问题 如何开启Spring容器对AspectJ注解的支持。 解决方案 在配置文件中引入aop schema,添加<aop:aspectj-autoproxy />配置。 ...

LiJIaming
2012/05/20
121
0

没有更多内容

加载失败,请刷新页面

加载更多

c++ 虚基类

c++ 虚基类 p556

天王盖地虎626
29分钟前
41
0
Java中的面向对象

一、面向对象 面向对象和面向过程的区别 过程就是函数,就是写方法,就是方法的一种实现。 对象就是将函数,属性的一种封装。用人们思考习惯的方式思考问题。 如何自定义类 修饰符 类名{ //成...

zhiruochujian
37分钟前
3
0
k8s删除Terminating状态的命名空间

背景: 我们都知道在k8s中namespace有两种常见的状态,即Active和Terminating状态,其中后者一般会比较少见,只有当对应的命名空间下还存在运行的资源,但是该命名空间被删除时才会出现所谓的...

Andy-xu
40分钟前
32
0
seata源码阅读笔记

seata源码阅读笔记 本文没有seata的使用方法,怎么使用seata可以参考官方示例,详细的很。 本文基于v0.8.0版本,本文没贴代码。 seata中的三个重要部分: TC:事务协调器,维护全局事务和分支...

东都大狼狗
53分钟前
21
0
Rust:最小化窗口后 CPU占用率高 (winit,glutin,imgui-rust)

最近试着用 imgui-rust 绘制界面,发现窗口最小化后CPU占用会增大。 查询的资料如下: https://github.com/rust-windowing/winit/issues/783 https://github.com/ocornut/imgui/issues/1151 ...

reter
57分钟前
32
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部