Spring-AOP源码分析随手记
Posted 一点学习的记录
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring-AOP源码分析随手记相关的知识,希望对你有一定的参考价值。
1.@EnableAspectJAutoProxy(proxyTargetClass = true)
就是弄了个"org.springframework.aop.config.internalAutoProxyCreator"::AnnotationAwareAspectJAutoProxyCreator.class的Bean到容器中
2.分析AnnotationAwareAspectJAutoProxyCreator.class类结构
得出了哪些是重要的几个。
3.查看AnnotationAwareAspectJAutoProxyCreator源码
=》查看父类AbstractAutoProxyCreator,有setBeanFactory等等各种继承来的方法
4.又是一顿整理得出了一个图(???)如下
pic1->AOP功能代码分析图
5.分析AbstractAutoProxyCreator。
setBeanFactory有个O标志被重写了,打开,有个initBeanFactory方法,打开,创建了个advisorRetrievalHelper切面工具,又是O重写 创建了aspectJAdvisorsBuilder
6.pic1图里明显看出有两个关键性方法:
postProcessBeforeInstantiation和postProcessAfterInitialization
显然是前后处理逻辑了。肯定先看前逻辑postProcessBeforeInstantiation啊
7.postProcessBeforeInstantiation
断点走起,居然是从这里进去的
所以这个之前分析IOC的createBean里的resolveBeforeInstantiation是AOP实现的关键。
8.分析postProcessBeforeInstantiation细节
8.1 isInfrastructureClass判断是否基础Bean
就是那种AOP本身的比如Advice、Pointcut、AopInfrastructureBean等,基础的这种直接返回不需要代理
8.2 shouldSkip是否要跳过(包含找出切面)
8.2.1找出增强器(那种切面里的@After、@Before的方法)
跟随断点跳跃到之前setBeanFactory创建的advisorRetrievalHelper里去了帮忙实现的找增强器
实际上这里面又分两部分了,一个是找事务的(findCandidateAdvisors)(本次断点容器和缓存中都就没用了直接返回空,不是事务,具体可以看aop源码instan...图)
另一部分是this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
跳进去看了下,它把所有的beanname拿出来找,去找切面类 找到了我写的MyLogAspect
(打了切面切面注解)
然后找到了切面类,调用相关封装的getAdvisors方法去拿增强器了。
其实就是获取切面类的所有方法(getAdvisorMethods)把每个包含增强那些注解的方法包装成Advice 放进缓存。
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
而
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
然后
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
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;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
switch判断注解类型 创建不同类型Advice 放进缓存
最终由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()找到了我写的所有切面的增强方法
最终把整个切面类放到了advisorsCache的ConcurrentHashMap,以切面类的beanname作为key,增强器方法advice集合作为value
9.postProcessAfterInitialization
条件断点,当beanname = "calculate"时停住。找出增强器后,看看后续aop是怎么和目标类结合的。
10.postProcessAfterInitialization细节
断点已达。老办法,看看是从哪调来的:
原来是这里,ioc创建完对象并给属性赋完值之后。
回到postProcessAfterInitialization本身,就调了个wrapIfNecessary。逻辑都在里面了
10.1 找对应的增强器
打开断点继续,先主要是个getAdvicesAndAdvisorsForBean然后调findEligibleAdvisors然后就是以前跑过的找事务略。然后主要是findAdvisorsThatCanApply(名字也看得出,它能用的 这个bean对应的切面),进去又是个canApply(candidate, clazz, hasIntroductions),这就是具体判断了:
获取所有方法,用匹配器match去匹配是否匹配上了
循环记下,全部找出来,找增强器就结束了!
10.2 织入生成代理对象
回到wrapIfNecessary开始创建代理对象了:
这里面框起来是涉及注解配置的,对应你配置的:
@EnableAspectJAutoProxy(exposeProxy = true)
@EnableAspectJAutoProxy(proxyTargetClass = true)
如果这两个设置了的话,就会处理实现。
第二个是启动优先cglib,第一个是把代理对象创建好之后暴露出去,这样就能让原本this.dadd去调用方法本来不能增强的情况 可以用
((Calculate) AopContext.currentProxy()).add(numA,numB);也触发增强效果
后面的话就是创建个代理工厂ProxyFactory,把增强器设置进去,最后调用getProxy
一路跳转:
这就是最后网上背背背的东西了。在没有接口和没打优先cglib的话用jdk创建否则cglib创建。
问题:
1.怎么得出来继承结构哪些是重要的、哪些是不需要看不重要的
2.怎么整理出来的?
以上是关于Spring-AOP源码分析随手记的主要内容,如果未能解决你的问题,请参考以下文章