Spring源码解析 -- 读取bean元数据
spring源码解析 -- 构造bean
spring源码解析 -- 注入属性
spring源码解析 -- Spring Context
Spring源码解析 -- AOP原理(1)
Spring源码解析 -- AOP原理(2)
Spring源码解析 -- SpringMvc原理
源码分析基于spring 4.3.x
本文通过阅读Spring源码,分析Spring AOP的功能是如何实现的。
关于阅读源码的思路,可参考 -- 如何阅读java源码
首先,明确几个概念
pointcut:切入点,根据方法名或者正则表达式去拦截一个方法。
advice:通知,在拦截到方法执行前或执行后的增强操作。
aspect:切面,一个切面可以包括多个切入点和通知,spring内部的切入点和通知是无序的。
advisor:只有一个通知和一个切入点的单元切面,可以看做一种特殊的aspect。
开始阅读源码前,本文主要关注的几个问题:
- xml中
<aop:aspectj-autoproxy/>
元素的作用 - spring如何根据Aspect注解创建切面
- spring如何根据切面信息创建代理对象
- spring是如何对多个通知进行链式调用的
<aop:aspectj-autoproxy/>
的作用
aspectj-autoproxy是spring内部定义的标签。
前面解析Spring读取bean元数据的文章说过,在spring中除了<beans>标签,其他标签需要编写一个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#parse
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的父类)
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
创建代理对象
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源码解析内容过长,关于多个通知链式调用的解析留到下一篇文章解析
如果您觉得本文不错,欢迎关注我的微信公众号,您的关注是我坚持的动力!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。