Spring AOP源码(二):BeanDefinition的准备工作

  在Spring容器中,要想创建AOP相关的对象就需要创建先准备好相关的beanDefinition信息,这里对于普通bean对象的beanDefinition准备不再赘述,仅介绍AOP的核心对象:AutoProxyCreator和Advisor的BeanDefinition对象的创建过程。

1、beanDefinition加载流程

  AOP相关的beanDefinition加载流程图

2、beanDefinition之间的关系

  beanDefinition的主要加载流程如上,会创建AOP常用的五种通知的BeanDefinition,分别是AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice、AspectJAroundAdvice,这五个Advice都只有有参的构造函数,所以在创建Advice的beanDefinition对象前,需要先创建好构造函数中参数的beanDefinition对象,分别是Method、 AspectJExpressionPointcut、 AspectInstanceFactory。
  在创建好Advice的beanDefinition对象后,创建Advisor的beanDefinition对象,对Advice对象做进一步的封装,Advisor只有有参构造函数,参数类型为Advice。
  核心流程:

  ConfigBeanDefinitionParser#parseAdvice Advisor封装成Advice的核心伪代码如下

 1 // 解析Advice
 2 private AbstractBeanDefinition parseAdvice(
 3       String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
 4       List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
 5 
 6       //  创建MethodLocatingFactoryBean的bean定义信息,MethodLocatingFactoryBean为Advice的构造函数中的参数
 7       RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
 8       methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
 9       methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
10       methodDefinition.setSynthetic(true);
11 
12       //  创建切面工厂定义实例, SimpleBeanFactoryAwareAspectInstanceFactory为Advice的构造函数中的参数
13       RootBeanDefinition aspectFactoryDef =
14             new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
15       aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
16       aspectFactoryDef.setSynthetic(true);
17 
18       //  获取Advice的beanDefinition信息
19       AbstractBeanDefinition adviceDef = createAdviceDefinition(
20             adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
21             beanDefinitions, beanReferences);
22         
23       // 配置Advisor切面,将Advisor封装为Advice
24       RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
25       advisorDefinition.setSource(parserContext.extractSource(adviceElement));
26       advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);  
27         
28       //  注册advisor定义信息
29       parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
30 
31       return advisorDefinition;
32   
33 }
  ConfigBeanDefinitionParser#createAdviceDefinition Advice有参构造函数的beanDefinition构建核心伪代码如下
 1 // AspectJMethodBeforeAdvice/after/around...等通知的有参构造函数中Menthod的参数索引位置
 2 private static final int METHOD_INDEX = 0;
 3 // AspectJMethodBeforeAdvice/after/around...等通知的有参构造函数中AspectJExpressionPointcut的参数索引位置
 4 private static final int POINTCUT_INDEX = 1;
 5 // AspectJMethodBeforeAdvice/after/around...等通知的有参构造函数中的AspectInstanceFactory参数索引位置
 6 private static final int ASPECT_INSTANCE_FACTORY_INDEX = 2;
 7 
 8 // 创建Advice的beanDefinition
 9 private AbstractBeanDefinition createAdviceDefinition(
10       Element adviceElement, ParserContext parserContext, String aspectName, int order,
11       RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
12       List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
13           
14    // 创建advice的bean定义信息
15    RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
16    adviceDefinition.setSource(parserContext.extractSource(adviceElement));
17    // 设置acpectName,此处的AspectName在后续的
18    adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
19 
20 
21    // advice构造函数参数 -> MethodLocatingFactoryBean设置在索引位置0
22    ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
23    cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
24 
25    Object pointcut = parsePointcutProperty(adviceElement, parserContext);
26 
27    // advice构造函数参数 -> pointcut相关信息设置在索引位置1
28    RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
29    cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
30    beanReferences.add(pointcutRef);
31    
32    // advice构造函数参数 -> aspectFactoryDef相关信息设置在索引位置2
33    cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
34 
35    return adviceDefinition;
36 }

  通过上述代码,可以将上述关系描述用下面的图片概括:

3、Spring内部的自动代理创建器BeanDefinition准备

  在加载aop的beanDefinition,会对pointcut、advisor、aspect等标签做解析,在解析这些标签之前,会优先注册AOP的自动代理构建器,用于后续AOP代理对象的创建。
  在获取AOP中Advice的beanDefinition之前,先注册代理模式的创建器ConfigBeanDefinitionParser#parse,核心代码如下
 1 // 解析
 2 public BeanDefinition parse(Element element, ParserContext parserContext) {
 3    CompositeComponentDefinition compositeDef =
 4          new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
 5    parserContext.pushContainingComponent(compositeDef);
 6    
 7    // 注册自动代理模式创建器,AspectjAwareAdvisorAutoProxyCreator
 8    configureAutoProxyCreator(parserContext, element);
 9    
10    // 解析aop:config子节点下的aop:pointcut/aop:advice/aop:aspect等标签元素
11    List<Element> childElts = DomUtils.getChildElements(element);
12    for (Element elt: childElts) {
13       // 获取标签名称
14       String localName = parserContext.getDelegate().getLocalName(elt);
15       // pointcut的解析
16       if (POINTCUT.equals(localName)) {
17          parsePointcut(elt, parserContext);
18       }
19       // advisor的解析
20       else if (ADVISOR.equals(localName)) {
21          parseAdvisor(elt, parserContext);
22       }
23       // aspect的解析
24       else if (ASPECT.equals(localName)) {
25          parseAspect(elt, parserContext);
26       }
27    }
28    parserContext.popAndRegisterContainingComponent();
29    return null;
30 }

  在这一步,默认的代理创建模式创建器为AspectjAwareAdvisorAutoProxyCreator,根据类图可知,该代理模式创建器为BeanPostProcessor。

  但是最终在IOC容器中的beanDefinitionMap里,代理模式创建器却不是AspectjAwareAdvisorAutoProxyCreator,而是AnnotationAwareAspectJAutoProxyCreator。

这个又是为什么呢?接着往下分析,通常我们在做AOP的相关配置时,肯定少不了如下配置:
1 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  这个配置的作用:自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。
  关于解析的核心代码AspectJAutoProxyBeanDefinitionParser#parse
1 // 解析<aop:aspectj-autoproxy/> 标签
2 public BeanDefinition parse(Element element, ParserContext parserContext) {
3    // 注册AnnotationAwareAspectJAutoProxyCreator
4    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
5    extendBeanDefinition(element, parserContext);
6    return null;
7 }

  AopConfigUtils#registerOrEscalateApcAsRequired:通过优优先级判断需要用哪个代理模式自动创建器。

 1 private static BeanDefinition registerOrEscalateApcAsRequired(
 2       Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
 3    // 如果已经存在了自动代理创建器且存在的自动代理创建器与现在不一致,那么需要根据优先级来判断到底需要使用哪个
 4    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
 5       BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
 6       if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
 7          // 获取已经存在的创建器的优先级
 8          int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
 9          // 获取当前要注册的创建器的优先级
10          int requiredPriority = findPriorityForClass(cls);
11          if (currentPriority < requiredPriority) {
12             apcDefinition.setBeanClassName(cls.getName());
13          }
14       }
15       // 如果已经存在自动代理创建器并且与将要创建的一致,那么无须再次创建
16       return null;
17    }
18 
19    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
20    beanDefinition.setSource(source);
21    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
22    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
23    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
24    return beanDefinition;
25 }

  在AopConfigUtils中的静态代码块中存储的有自动代理创建器的优先级,通过静态代码块可知,AspectJAwareAdvisorAutoProxyCreator的优先级是1,AnnotationAwareAspectJAutoProxyCreator的优先级是2,所以解析过程中,会将原有的创建器AspectjAwareAdvisorAutoProxyCreator做替换。

1 // 自动代理创建器优先级缓存
2 private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
3 
4 static {
5    // Set up the escalation list...
6    APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
7    APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
8    APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
9 }

  AnnotationAwareAspectJAutoProxyCreator的类图关系如下,AnnotationAwareAspectJAutoProxyCreator也继承了BeanPostProcessor接口,这个结论先记下,在下一章节中再做详述。

posted @ 2022-12-27 20:03  无虑的小猪  阅读(127)  评论(0编辑  收藏  举报