spring整套源码系列之【aop解析切面源码】
2024-04-10 18:44:09 0 举报
spring整套源码系列之【aop解析切面源码】
作者其他创作
大纲/内容
//把切面中的通知构造为一个一个的advice通知对象\t\t\tthis.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
属性赋值
这里做了dcl检查,后面还有个重复判断aspectNames == null
用于缓存我们的切面信息的名称List<String> aspectNames = this.aspectBeanNames;
调用
//找出Aspect相关的信息之后封装为一个advisoradvisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
//通过beanName去容器中获取到对应class对象\t\t\t\t\t\tClass<?> beanType = this.beanFactory.getType(beanName);
@EnableAspectJAutoProxy
//找出相关的advisor List<Advisor> advisors = super.findCandidateAdvisors();
是否存在注解标记
这里就是解析我们Aspect的地方,也就是解析高版本aop写法【在第一个bean创建的时候解析,后面就不解析了
去我们的容器中获取到实现了Advisor接口的实现类advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors()
invoke执行(自然里面也会先getBean)
return
构建advice通知
在我们的创建Bean的流程中还没调用构造器来实例化bean的时候进行调用(实例化前后) 我们的aop 解析切面 以及事务解析事务注解都是在这里完成的
pointcut
设置Expression表达式信息ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
创建bean定义
加入到保存切面类名的缓存中,下一次判断不为空就不会在解析了aspectNames.add(beanName);
通过 通知者探测器来帮助我们找到通知advisorRetrievalHelper.findAdvisorBeans();
aspectNames == null
不存在遍历下一个方法
注意下是调用到
这里就是兼容低版本的aop写法,也就是我们前面自己new 的advisor,我们注解方式的自然是找不到
getAdvice(...)
return advisors;
//获取我们的标记为Aspect的类\t\tClass<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
aspectBeanNames是用volatile修饰的,为空才会解析,保证不会在每个bean创建的时候都去解析aop(防止重复解析),而且在解析前加了锁
postProcessBeforeInstantiation()
AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar所以会在解析@Import注解的时候调用它的registerBeanDefinitions()方法
是
解析配置类
ImportBeanDefinitionRegistrarregisterBeanDefinitions()
否
synchronized (this)
根据注解类型创建相应的advice类型对象
判断当前声明Aspect注解的bean是否为单例this.beanFactory.isSingleton(beanName)
span style=\"font-size: inherit;\
advice
//判断是不是切面this.advisorFactory.isAspect(beanType)
只有说自己构建的advisor才会走!=0操作,老版本了不分析
getBean()
#AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors();
构建pointcut切点表达式对象
//获取切面方法上的注解 findAspectJAnnotationOnMethod(candidateAdviceMethod);
把获取到的advisor放入return列表advisors.addAll(classAdvisors);
这里是解析接口方式实现aop的地方,直接从类中找有没有实现了advisor的bean定义
advisorList
return new ArrayList<>();
第一次调用bean后置处理器用来解析切面
registerBeanDefinitions()#AspectJAutoProxyRegistrar
aop功能中在这里传入的是Object对象,代表去容器中获取到所有的组件的名称,然后再经过一一的进行遍历,这个过程是十分的消耗性能的,所以说spring会再这里加入了保存切面信息的缓存。但是事务功能不一样,事务模块的功能是直接去容器中获取Advisor类型的,选择范围小,且不消耗性能。所以spring在事务模块中没有加入缓存来保存我们的事务相关的advisor
advisor
//根据class对象判断是不是切面this.advisorFactory.isAspect(beanType)
判断方法上是否存在相关注解标注findAspectJAnnotationOnMethod(candidateAdviceMethod)
//直接从缓存中取return this.advisorsCache.get(aspectName);
doCreateBean()
解析出来不为空加到返回集合中advisors.add(advisor);
//获取我们的切面类的class对象Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
return ajexp 【pointcut】
//获取到切面类中的所有方法,但是不包括标注了@PointCut注解的方法getAdvisorMethods(aspectClass)
否--continue
解析完成
找到候选的Advisors(通知者也可以说成增强器对象)List<Advisor> candidateAdvisors = findCandidateAdvisors();
for循环遍历beanNames执行
@Nullable //advice实例 private Advice instantiatedAdvice;//pointcut实例private final AspectJExpressionPointcut declaredPointcut;.......
InstantiationAwareBeanPostProcessor
advisorNames.length == 0
//真正的去获取我们的advisor实例 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
this为aspectJAdvisorsBuilder,为了防止多线程重复解析
入口1
有没有切面注解(就是看类上有没有Aspect注解) && 不是有AJC进行编译的(hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
开始构建pointcut
一个注解都没有则遍历下一个方法
这个地方如果跟的话注意下,this为AnnotationAwareAspectJAutoProxyCreator所以后面调用需要注意
解析@Import
for循环解析
这里主要是注册bean后置处理器,后置处理器解析切面AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
判断方法是否标记了Before、After等相关注解
一样是判断是否存在before、after等注解,有才处理
AspectJAutoProxyRegistrar
入口2
//返回我们所有的通知\t\treturn advisors;
//校验我们的切面类\t\tvalidate(aspectClass);
0 条评论
下一页