Spring源码解析 -- AOP原理(1)

Spring源码解析 -- 读取bean元数据
spring源码解析 -- 构造bean
spring源码解析 -- 注入属性
spring源码解析 -- Spring Context
Spring源码解析 -- AOP原理(1)
Spring源码解析 -- AOP原理(2)
Spring源码解析 -- SpringMvc原理java

源码分析基于spring 4.3.x
本文经过阅读Spring源码,分析Spring AOP的功能是如何实现的。
关于阅读源码的思路,可参考 -- 如何阅读java源码正则表达式

首先,明确几个概念
pointcut:切入点,根据方法名或者正则表达式去拦截一个方法。
advice:通知,在拦截到方法执行前或执行后的加强操做。
aspect:切面,一个切面能够包括多个切入点和通知,spring内部的切入点和通知是无序的。
advisor:只有一个通知和一个切入点的单元切面,能够看作一种特殊的aspect。spring

开始阅读源码前,本文主要关注的几个问题:express

  1. xml中<aop:aspectj-autoproxy/>元素的做用
  2. spring如何根据Aspect注解建立切面
  3. spring如何根据切面信息建立代理对象
  4. spring是如何对多个通知进行链式调用的

<aop:aspectj-autoproxy/> 的做用

aspectj-autoproxy是spring内部定义的标签。
前面解析Spring读取bean元数据的文章说过,在spring中除了标签,其余标签须要编写一个NamespaceHandlerSupport实现类来完成标签解析工做。
在spring源码中搜索一下,就能够发现aspectj-autoproxy的解析类AopNamespaceHandler缓存

public void init() {
	this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
	this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
	this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
	this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
复制代码

而AspectJAutoProxyBeanDefinitionParser类负责对aspectj-autoproxy标签进行解析: AspectJAutoProxyBeanDefinitionParser#parsebash

public BeanDefinition parse(Element element, ParserContext parserContext) {
	AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
	extendBeanDefinition(element, parserContext);
	return null;
}
复制代码

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary -> AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary微信

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, Object source) {
	return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
复制代码

这里将AnnotationAwareAspectJAutoProxyCreator注入到spring上下文环境中。
AnnotationAwareAspectJAutoProxyCreator是一个关键的类,继承了BeanPostProcessor接口,它负责完成建立切面工做。源码分析

建立advisor

AbstractAutoProxyCreator#postProcessAfterInitialization -> AbstractAutoProxyCreator#wrapIfNecessary (AbstractAutoProxyCreator是AnnotationAwareAspectJAutoProxyCreator的父类)post

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	...
	
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);	// #1
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		Object proxy = createProxy(
				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));	// #2
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	}

	this.advisedBeans.put(cacheKey, Boolean.FALSE);
	return bean;
}
复制代码

#1 根据bean元数据构造通知和单元切面
#2 建立代理对象ui

getAdvicesAndAdvisorsForBean -> AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean -> AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	List<Advisor> candidateAdvisors = findCandidateAdvisors();	// #1
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);	// #2
	extendAdvisors(eligibleAdvisors);	// #3
	if (!eligibleAdvisors.isEmpty()) {
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);	// #4
	}
	return eligibleAdvisors;
}
复制代码

这是一个很是重要的方法,实现了几个关键步骤
#1 findCandidateAdvisors -- 查找全部的单元切面(第一次会建立)
#2 findAdvisorsThatCanApply -- 根据目标bean的class过滤一部分的单元切面
#3 extendAdvisors -- 扩充单元切面列表,spring会根据须要添加一些内部使用的单元切面
#4 sortAdvisors -- 对单元切面排序

查找全部的单元切面

findCandidateAdvisors -> AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors -> BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

public List<Advisor> buildAspectJAdvisors() {
	List<String> aspectNames = this.aspectBeanNames;

	if (aspectNames == null) {
		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {	// #1
				List<Advisor> advisors = new LinkedList<Advisor>();
				aspectNames = new LinkedList<String>();
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				for (String beanName : beanNames) {	// #2
					if (!isEligibleBean(beanName)) {	// #3
						continue;
					}
					// We must be careful not to instantiate beans eagerly as in this case they
					// would be cached by the Spring container but would not have been weaved.
					Class<?> beanType = this.beanFactory.getType(beanName);
					if (beanType == null) {
						continue;
					}
					if (this.advisorFactory.isAspect(beanType)) {	// #4
						aspectNames.add(beanName);
						AspectMetadata amd = new AspectMetadata(beanType, beanName);	// #5
						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
							MetadataAwareAspectInstanceFactory factory =
									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);	// #6
							if (this.beanFactory.isSingleton(beanName)) {	// #7
								this.advisorsCache.put(beanName, classAdvisors);
							}
							else {
								this.aspectFactoryCache.put(beanName, factory);
							}
							advisors.addAll(classAdvisors);	// #8
						}
						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;
			}
		}
	}

	... #9
}		
复制代码

#1 典型的double check
#2 遍历全部的bean
#3 判断是否为合格的切面类
#4 是否为切面类(是否有Aspect注解)
#5 获取切面信息
#6 构建一系列的单元切面
#7 加入缓存
#8 加入结果
#9 缓存不为空,从缓存中获取数据返回

步骤#6调用ReflectiveAspectJAdvisorFactory.getAdvisors

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

	MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
			new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);	// #1

	List<Advisor> advisors = new LinkedList<Advisor>();
	for (Method method : getAdvisorMethods(aspectClass)) {	// #2
		Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);	// #3
		if (advisor != null) {
			advisors.add(advisor);
		}
	}
	...
	return advisors;
}

复制代码

#1 lazySingletonAspectInstanceFactory对getAspectInstance进行了缓存,保证getAspectInstance方法返回单例
#2 getAdvisorMethods获取全部没有Pointcut注解的方法(有Pointcut注解的方法不多是Advisor)
#3 使用方法元数据构造单元切面

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

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

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

	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
			this, aspectInstanceFactory, declarationOrderInAspect, aspectName);	// #2
}	
复制代码

#1 获取切入点Pointcut,并构建了AspectJExpressionPointcut
#2 建立单元切面InstantiationModelAwarePointcutAdvisorImpl,该类中包含属性 -- 被拦截类declaringClass,被拦截方法aspectJAdviceMethod,切入点declaredPointcut和通知instantiatedAdvice。

InstantiationModelAwarePointcutAdvisorImpl#构造方法 -> InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice -> ReflectiveAspectJAdvisorFactory#getAdvice

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
		MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

	... // #1

	AbstractAspectJAdvice springAdvice;

	switch (aspectJAnnotation.getAnnotationType()) {	// #2
		case AtBefore:
			springAdvice = new AspectJMethodBeforeAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfter:
			springAdvice = new AspectJAfterAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfterReturning:
			springAdvice = new AspectJAfterReturningAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
			springAdvice = new AspectJAfterThrowingAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		case AtAround:
			springAdvice = new AspectJAroundAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtPointcut:
			if (logger.isDebugEnabled()) {
				logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
			}
			return null;
		default:
			throw new UnsupportedOperationException(
					"Unsupported advice type on method: " + candidateAdviceMethod);
	}

	// Now to configure the advice...
	springAdvice.setAspectName(aspectName);
	springAdvice.setDeclarationOrder(declarationOrder);
	String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
	if (argNames != null) {
		springAdvice.setArgumentNamesFromStringArray(argNames);
	}
	springAdvice.calculateArgumentBindings();
	return springAdvice;
}

复制代码

#1 aspectInstanceFactory#getAspectMetadata获取切面信息,再获取对应的aspectJAnnotation
#2 根据切面类型,构建不一样的通知实现类
@After对应AspectJAfterAdvice
@Around对应AspectJAroundAdvice
@Before对应AspectJMethodBeforeAdvice
@AfterReturning对应AspectJAfterReturningAdvice
@AfterThrowing对应AspectJAfterThrowingAdvice
除了AspectJAroundAdvice,这些通知实现类都实现了MethodInterceptor(方法拦截器接口)。

findAdvisorsThatCanApply 过滤单元切面

这里会遍历全部的单元切面,检查bean的class和class中是否有方法能够匹配对应的单元切面,若是没有则过滤该单元切面。代码比较繁琐,不展开了。

extendAdvisors(eligibleAdvisors)扩充单元切面

AspectJAwareAdvisorAutoProxyCreator.extendAdvisors -> AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary

spring会在advisors列表开始位置添加ExposeInvocationInterceptor。 ExposeInvocationInterceptor是一个特殊的MethodInterceptor,它将当前方法拦截器调用链放置到线程上下文中,以便有须要时使用。

建立代理对象

咱们知道,spring经过动态代理类实现aop,有jdk动态代理和cglib两种方法。
若是要使用jdk动态代理,被代理类必须实现一个接口。
这里只关注jdk动态代理如何实现aop。

AbstractAutoProxyCreator#wrapIfNecessary方法#2步骤 -> AbstractAutoProxyCreator.createProxy(第三个参数就是Advices)

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

	...
	
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);	// #1
	for (Advisor advisor : advisors) {
		proxyFactory.addAdvisor(advisor);	// #2
	}

	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

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

	return proxyFactory.getProxy(getProxyClassLoader());	// #3
}			
复制代码

#1 类型检查及转化,如将Advices转换成Advisor
#2 将Advisor添加到proxyFactory中
#3 构造代理对象

proxyFactory.getProxy -> ProxyCreatorSupport.createAopProxy

protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();
	}
	return getAopProxyFactory().createAopProxy(this);	// #1
}
复制代码

#1 构造代理对象,createAopProxy方法参数是this,将proxyFactory将自身做为参数,

DefaultAopProxyFactory#createAopProxy

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {	// #1
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {	// #2
		return new JdkDynamicAopProxy(config);
	}
}
复制代码

#1 根据用户配置和目标bean是否有实现接口,判断是否须要使用ObjenesisCglibAopProxy #2 使用JDK动态代理

来看看JdkDynamicAopProxy#getProxy

public Object getProxy(ClassLoader classLoader) {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
	}
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);	// #1
}
复制代码

#1 这里构造了jdk的动态代理对象,注意newProxyInstance方法第三个参数是this,即JdkDynamicAopProxy,JdkDynamicAopProxy实现了InvocationHandler。

Spring AOP源码解析内容过长,关于多个通知链式调用的解析留到下一篇文章解析

若是您以为本文不错,欢迎关注个人微信公众号,您的关注是我坚持的动力!

相关文章
相关标签/搜索