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


声明:本文转载自https://my.oschina.net/u/2377110/blog/1529575,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

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:pointcut>和<aop: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.注解配置

不论是通过&lt;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的原理能够有深入的理解,期待大家的交流!

本文发表于2017年09月06日 12:36
(c)注:本文转载自https://my.oschina.net/u/2377110/blog/1529575,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1696 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1