首页 > 编程语言 >Spring AOP源码(二):BeanDefinition的准备工作

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

时间:2022-12-27 20:12:42浏览次数:46  
标签:RootBeanDefinition parserContext Spring Advice 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接口,这个结论先记下,在下一章节中再做详述。

标签:RootBeanDefinition,parserContext,Spring,Advice,AOP,源码,创建,构造函数,beanDefinition
From: https://www.cnblogs.com/RunningSnails/p/17008883.html

相关文章

  • SpringBoot - 文件上传
    Java代码@RestControllerpublicclassTestController{//单文件或多文件上传@PostMapping("/file/upload")publicStringfileUpload(@RequestParam(......
  • Spring AOP源码(一):源码分析示例
    1、aop.xml配置文件1<?xmlversion="1.0"encoding="UTF-8"?>2<beansxmlns="http://www.springframework.org/schema/beans"3xmlns:xsi="http://www.w3.......
  • SpringBoot - 全局异常处理@RestControllerAdvice,@ControllerAdvice,@ExceptionHandler
    @RestControllerAdvice与@ControllerAdvice 作用:告诉框架这是一个异常处理类,@RestControllerAdvice返回的是响应体范围:类上 @ExceptionHandler 作用:发生特定类型的......
  • SpringBoot - 目录
    SpringBoot-@Configuration,@Bean,@Scope组件注入容器SpringBoot-MVC三层架构注解注入到容器中与从IOC容器获取实例注解SpringBoot-配置包扫描注解@ComponentScanS......
  • AS3 IOC框架Spring Actionscript 的使用总结
    SpringActionscript 是众多围绕依赖注入提供解决方案的Flex控制反转框架之一AS3下经典的IOC框架有SpringActionScript、Parsley、Flicc和Swiz,由于我对JAVAspringIOC机......
  • Nacos1.4源码(1):客户端注册源码
    搭建环境搭建Nacos服务端环境从github上下载nacos1.4源码下来:https://github.com/alibaba/nacos下载下来,源码编译好,直接idea运行com.alibaba.nacos.Nacos类就行:那我......
  • 我是怎么调试 Element UI 源码的
    ​​上篇文章​​写了怎么调试antd的源码,反响很不错:但很多小伙伴是写Vue的,可能平时用的是ElementUI的组件库,所以这篇文章就来讲下怎么调试ElementUI的源码。首先,......
  • Spring安全和角度(二)
    使用OAuth2进行单点登录在本节中,我们继续我们的讨论如何使用弹簧安全跟角在“单页应用程序”中。在这里,我们展示如何使用春季安全密钥䋰春云将我们的API网关扩展到后端......
  • SpringBoot - 自定义拦截器HandlerInterceptor
    1.实现HandlerInterceptor接口/***自定义拦截器*/publicclassMyInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(Htt......
  • SpringBoot - 转换器Convert与SpringBoot支持的返回类型
    1.自定义转换器@Configuration(proxyBeanMethods=false)publicclassAppConfig{@BeanpublicWebMvcConfigurergetWebMvcConfigurer(){returnn......