学一学Sping中的AOP【XML标签解析】

215 阅读11分钟

Spring版本: 5.3.27

AspectJ版本: 1.9.22

JDK版本: 1.8

1、前置说明

概念性的东西理解起来都会比较抽象,下面的一些概念可以一扫而过,有个大致印象就行。

先学会使用,再分析原理,回过头来再看这些概念就会一一对应上。

1.1前置概念

1.1.1基础概念

  • AOP( Aspect-Oriented Programming) :一种编程范式(面向切面编程),通过将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,实现了模块化和解耦。

  • 通知(Advice) :通知是指在特定的切入点(Join Point)上执行的动作。Spring AOP支持以下几种类型的通知:

    1. 前置通知(Before Advice) :在目标方法执行之前运行的通知。
    2. 后置通知(After Advice) :在目标方法执行之后运行的通知,且无论方法是否成功执行都会执行。
    3. 返回通知(After Returning Advice) :目标方法成功执行并返回结果之后运行的通知。
    4. 异常通知(After Throwing Advice) :目标方法抛出异常时运行的通知。
    5. 环绕通知(Around Advice) :通知包裹目标方法的执行,可以控制目标方法的执行时机,甚至可以决定是否执行目标方法。
  • 切面(Aspect) :切面是通知和切点的结合。一个切面可以包含一个或多个通知,并定义在哪些切点上应用这些通知。切面封装了横切关注点,使其易于复用和管理。

  • 切点(Pointcut) :切点是指能够插入通知的特定连接点(Join Point)。Spring使用切点表达式来定义哪些方法或执行点会被拦截。常见的切点表达式基于方法签名、类、注解等进行匹配。

  • 连接点(Join Point) :连接点是指程序执行过程中可以插入切面的具体位置,通常是方法的执行。每个连接点都是潜在的切点。

  • 目标对象(Target Object) :目标对象是指被AOP代理的实际对象,它包含了业务逻辑。在AOP中,目标对象的所有方法(根据切点的匹配条件)都有可能被拦截并应用通知。

  • 代理(Proxy) :代理是指AOP框架创建的动态代理对象,它代替目标对象处理横切逻辑。在Spring AOP中,代理有两种实现方式: 1.JDK动态代理:适用于实现接口的类。 2.CGLIB代理:适用于没有实现接口的类,通过生成子类的方式创建代理。

  • 织入(Weaving) :织入是将切面逻辑应用到目标对象的过程。Spring AOP是基于运行时动态代理的织入方式,不需要对字节码进行修改,属于动态织入。


1.1.2Advisor和Advised

  1. Advisor

    • Advisor是Spring AOP中一个更高层次的概念,它是通知(Advice)和切点(Pointcut)的结合。可以认为它是一个带有条件的通知
    • 一个Advisor包含了一个通知和一个切点,用来定义在特定的切入点上应该执行哪个通知。例如,某个Advisor可能指定在调用某个类的特定方法时执行前置通知。
    • 在Spring中,org.springframework.aop.Advisor接口用于定义这种结构。常见的AdvisorDefaultPointcutAdvisor,它允许你为某个切点绑定一个具体的通知。
  2. Advised

    • Advised是Spring AOP框架中一个被增强(advised)对象的抽象接口。这个接口允许对目标对象应用不同的增强逻辑(advice),并通过代理对象执行这些增强操作。
    • 在Spring中,org.springframework.aop.framework.Advised接口提供了管理增强和代理的能力。它允许开发者动态地增加或删除通知、控制代理行为等。

1.1.3Spring AOP 和 AspectJ

  1. Spring AOP

    • 代理机制:Spring AOP是基于动态代理的实现,使用JDK动态代理或CGLIB字节码生成来创建代理对象。它只支持方法级别的AOP,无法像AspectJ那样拦截字段、构造函数等其他结构。
    • 织入方式:Spring AOP属于运行时织入,代理对象在运行时生成,适合于大多数基于Spring的项目。
    • 易用性:Spring AOP集成在Spring框架中,使用起来更加简洁灵活,特别适合面向Spring Bean的AOP需求。
  2. AspectJ

    • 编译时增强:AspectJ是一种静态编译时AOP框架,它不仅可以拦截方法,还可以拦截字段、构造函数等。AspectJ通过字节码修改的方式实现织入,增强代码在编译时(或类加载时)已经被注入到目标对象中,称为编译时织入类加载时织入
    • 强大灵活:AspectJ的切点表达式更强大,它能够定义更复杂的匹配规则和拦截粒度,超越了Spring AOP的能力。
    • 性能:由于AspectJ在编译时已经将增强逻辑注入到目标类中,执行时无需动态代理,因此它的性能相对较高。
  3. Spring AOP 和 AspectJ 的集成 Spring提供了与AspectJ的集成,通过@AspectJ注解驱动的风格,Spring允许使用AspectJ的注解语法,同时利用Spring AOP的代理机制。集成方式包括:

    • 基于注解的切面编程:通过@Aspect@Before@After等注解,开发者可以像在AspectJ中一样定义切面和通知,但仍然使用Spring AOP的动态代理。
    • AspectJ代理模式:如果需要使用AspectJ的编译时或类加载时织入,Spring可以使用<aop:aspectj-autoproxy/>@EnableAspectJAutoProxy开启AspectJ的功能。

1.2测试样例

1.2.1测试类

 package com.lazy.snail;
 ​
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 ​
 @Slf4j
 public class SpringTest {
     @Test
     void test() {
         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     }
 }

1.2.2applicationContext.xml

 <?xml version="1.0" encoding="UTF-8" ?>
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
     <aop:aspectj-autoproxy/>
 </beans>
 <!-- pom文件增加AspectJ依赖 -->
 <dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.22</version>
 </dependency>

1.3源码入口

refresh方法中obtainFreshBeanFactory方法创建、配置容器后,加载bean定义信息。

 // AbstractRefreshableApplicationContext
 protected final void refreshBeanFactory() throws BeansException {
     // 省略部分代码
     try {
         // 创建默认容器
         DefaultListableBeanFactory beanFactory = createBeanFactory();
         beanFactory.setSerializationId(getId());
         // 容器配置
         customizeBeanFactory(beanFactory);
         // 加载bean定义信息
         loadBeanDefinitions(beanFactory);
         this.beanFactory = beanFactory;
     } catch (IOException ex) {
         throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
     }
 }

2、解析<aop:aspectj-autoproxy/>

 // DefaultBeanDefinitionDocumentReader
 /**
  * 注册</beans>中的bean定义信息
  */
 protected void doRegisterBeanDefinitions(Element root) {
     // 省略部分代码...
 ​
     preProcessXml(root);
     // 解析bean定义信息
     parseBeanDefinitions(root, this.delegate);
     postProcessXml(root);
 ​
     this.delegate = parent;
 }
 ​
 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
     if (delegate.isDefaultNamespace(root)) {
         NodeList nl = root.getChildNodes();
         for (int i = 0; i < nl.getLength(); i++) {
             Node node = nl.item(i);
             if (node instanceof Element) {
                 Element ele = (Element) node;
                 if (delegate.isDefaultNamespace(ele)) {
                     parseDefaultElement(ele, delegate);
                 } else {
                     // 解析[aop:aspectj-autoproxy: null]
                     delegate.parseCustomElement(ele);
                 }
             }
         }
     }
     else {
         delegate.parseCustomElement(root);
     }
 }
 // BeanDefinitionParserDelegate
 public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
     String namespaceUri = getNamespaceURI(ele);
     if (namespaceUri == null) {
         return null;
     }
     // spring.handlers
     // http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
     // resolve方法会从一个集合找到"http://www.springframework.org/schema/aop"对应的全限定名
     // 实例化AopNamespaceHandler,调用init方法
     NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
     if (handler == null) {
         error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
         return null;
     }
     // parse方法是父类NamespaceHandlerSupport的
     return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
 }

AopNamespaceHandler的init方法注册了一些解析器:

 // AopNamespaceHandler extends NamespaceHandlerSupport
 public void init() {
     // In 2.0 XSD as well as in 2.5+ XSDs
     registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
     registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
     registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
 ​
     // Only in 2.0 XSD: moved to context namespace in 2.5+
     registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
 }

image-20241022232821176

下面的解析过程实际就是往容器注册了一个名为org.springframework.aop.config.internalAutoProxyCreator,beanClass为AnnotationAwareAspectJAutoProxyCreator的beanDefinition。

 // NamespaceHandlerSupport
 public BeanDefinition parse(Element element, ParserContext parserContext) {
     // parser-->AspectJAutoProxyBeanDefinitionParser
     BeanDefinitionParser parser = findParserForElement(element, parserContext);
     return (parser != null ? parser.parse(element, parserContext) : null);
 }
 ​
 // AspectJAutoProxyBeanDefinitionParser
 public BeanDefinition parse(Element element, ParserContext parserContext) {
     AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
     extendBeanDefinition(element, parserContext);
     return null;
 }
 ​
 // AopNamespaceUtils
 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
         ParserContext parserContext, Element sourceElement) {
 ​
     BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
             parserContext.getRegistry(), parserContext.extractSource(sourceElement));
     useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
     registerComponentIfNecessary(beanDefinition, parserContext);
 }
 ​
 // AopConfigUtils
 public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
         BeanDefinitionRegistry registry, @Nullable Object source) {
 ​
     return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
 }
 ​
 private static BeanDefinition registerOrEscalateApcAsRequired(
         Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
 ​
     Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
 ​
     // 省略部分代码...
     // cls --> AnnotationAwareAspectJAutoProxyCreator
     RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
     beanDefinition.setSource(source);
     beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
     beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
     // AUTO_PROXY_CREATOR_BEAN_NAME =
             "org.springframework.aop.config.internalAutoProxyCreator"
     registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
     return beanDefinition;
 }

refresh方法中registerBeanPostProcessors方法实例化了AnnotationAwareAspectJAutoProxyCreator

image-20241023004108757

3、解析<aop:config>

在applicationContext.xml中新增了如下内容:

 <!-- 被代理的类 -->
 <bean id="work" class="com.lazy.snail.aop.Work"/>
 ​
 <!-- 切面 -->
 <bean id="myAspect" class="com.lazy.snail.aop.MyAspect"/>
 ​
 <!-- aop配置 -->
 <aop:config>
     <aop:aspect ref="myAspect">
         <aop:before method="beforeWork" pointcut-ref="myPointcut"/>
         <aop:pointcut id="myPointcut" expression="execution(public void com.lazy.snail.aop.Work.doWork())"/>
     </aop:aspect>
 </aop:config>

aop:config解析

 // NamespaceHandlerSupport
 public BeanDefinition parse(Element element, ParserContext parserContext) {
     // parser-->ConfigBeanDefinitionParser
     BeanDefinitionParser parser = findParserForElement(element, parserContext);
     return (parser != null ? parser.parse(element, parserContext) : null);
 }
 ​
 // ConfigBeanDefinitionParser
 public BeanDefinition parse(Element element, ParserContext parserContext) {
     CompositeComponentDefinition compositeDef =
             new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
     parserContext.pushContainingComponent(compositeDef);
     // 配置自动代理构建器,基本没干活,在解析<aop:aspectj-autoproxy/>时已经创建自动代理构建器
     configureAutoProxyCreator(parserContext, element);
     
     // 获取子节点 <aop:aspect
     List<Element> childElts = DomUtils.getChildElements(element);
     for (Element elt: childElts) {
         String localName = parserContext.getDelegate().getLocalName(elt);
         if (POINTCUT.equals(localName)) {
             parsePointcut(elt, parserContext);
         }else if (ADVISOR.equals(localName)) {
             parseAdvisor(elt, parserContext);
         }else if (ASPECT.equals(localName)) {
             // 解析切面
             parseAspect(elt, parserContext);
         }
     }
 ​
     parserContext.popAndRegisterContainingComponent();
     return null;
 }
 ​
 private void parseAspect(Element aspectElement, ParserContext parserContext) {
     String aspectId = aspectElement.getAttribute(ID);
     String aspectName = aspectElement.getAttribute(REF);
 ​
     try {
         this.parseState.push(new AspectEntry(aspectId, aspectName));
         List<BeanDefinition> beanDefinitions = new ArrayList<>();
         List<BeanReference> beanReferences = new ArrayList<>();
 ​
         List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
         for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
             Element declareParentsElement = declareParents.get(i);
             beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
         }
         
         // <aop:aspect的子节点 <aop:before 、<aop:pointcut
         NodeList nodeList = aspectElement.getChildNodes();
         boolean adviceFoundAlready = false;
         for (int i = 0; i < nodeList.getLength(); i++) {
             Node node = nodeList.item(i);
             if (isAdviceNode(node, parserContext)) {
                 if (!adviceFoundAlready) {
                     adviceFoundAlready = true;
                     if (!StringUtils.hasText(aspectName)) {
                         parserContext.getReaderContext().error(
                                 "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
                                 aspectElement, this.parseState.snapshot());
                         return;
                     }
                     beanReferences.add(new RuntimeBeanReference(aspectName));
                 }
                 // 从配置信息中构建了advisor的bean定义信息注册到容器
                 AbstractBeanDefinition advisorDefinition = parseAdvice(
                         aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
                 beanDefinitions.add(advisorDefinition);
             }
         }
 ​
         AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
                 aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
         parserContext.pushContainingComponent(aspectComponentDefinition);
         
         // <aop:pointcut id="myPointcut" expression="execution(public void com.lazy.snail.aop.Work.doWork())"/>
         List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
         for (Element pointcutElement : pointcuts) {
             parsePointcut(pointcutElement, parserContext);
         }
 ​
         parserContext.popAndRegisterContainingComponent();
     }
     finally {
         this.parseState.pop();
     }
 }
 ​
 /**
  * 解析注册'before', 'after', 'after-returning', 'after-throwing' 或者 'around'
  */
 private AbstractBeanDefinition parseAdvice(
         String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
         List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
 ​
     try {
         this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
 ​
         // 创建MethodLocatingFactoryBean
         RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
         methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
         methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
         methodDefinition.setSynthetic(true);
 ​
         // 创建SimpleBeanFactoryAwareAspectInstanceFactory
         RootBeanDefinition aspectFactoryDef =
                 new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
         aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
         aspectFactoryDef.setSynthetic(true);
 ​
         // 本例adviceDef是AspectJMethodBeforeAdvice的bean定义信息
         AbstractBeanDefinition adviceDef = createAdviceDefinition(
                 adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
                 beanDefinitions, beanReferences);
 ​
         // 配置advisor
         RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
         advisorDefinition.setSource(parserContext.extractSource(adviceElement));
         advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
         if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
             advisorDefinition.getPropertyValues().add(
                     ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
         }
         // 把advisor注册到容器
         // 向容器注册一个名为"org.springframework.aop.aspectj.AspectJPointcutAdvisor#0"的bean定义信息
         parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
 ​
         return advisorDefinition;
     }
     finally {
         this.parseState.pop();
     }
 }
 ​
 private AbstractBeanDefinition createAdviceDefinition(
         Element adviceElement, ParserContext parserContext, String aspectName, int order,
         RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
         List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
     
     // getAdviceClass根据不同的adviceElement返回不同的通知实现类
     // before --> AspectJMethodBeforeAdvice.class
     RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
     adviceDefinition.setSource(parserContext.extractSource(adviceElement));
 ​
     adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
     adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
 ​
     // 省略部分代码...
 ​
     ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
     cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
     
     // 解析切点
     // 本例中配置了pointcut-ref="myPointcut" 将返回字符串"myPointcut"
     Object pointcut = parsePointcutProperty(adviceElement, parserContext);
     // 配置的pointcut
     if (pointcut instanceof BeanDefinition) {
         cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
         beanDefinitions.add((BeanDefinition) pointcut);
     } else if (pointcut instanceof String) { // 配置的pointcut-ref
         RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
         cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
         beanReferences.add(pointcutRef);
     }
 ​
     cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
     // 最终得到了带有三个构造参数的AspectJMethodBeforeAdvice的bean定义信息
     return adviceDefinition;
 }
 ​
 private Object parsePointcutProperty(Element element, ParserContext parserContext) {
     // 不能同时配置pointcut和pointcut-ref
     if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
             parserContext.getReaderContext().error(
                     "Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
                     element, this.parseState.snapshot());
             return null;
         } else if (element.hasAttribute(POINTCUT)) { // pointcut
             // 创建匿名的切点
             String expression = element.getAttribute(POINTCUT);
             AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
             pointcutDefinition.setSource(parserContext.extractSource(element));
             return pointcutDefinition;
         } else if (element.hasAttribute(POINTCUT_REF)) { // pointcut-ref
             String pointcutRef = element.getAttribute(POINTCUT_REF);
             if (!StringUtils.hasText(pointcutRef)) {
                 parserContext.getReaderContext().error(
                         "'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
                 return null;
             }
             return pointcutRef;
         } else {
             parserContext.getReaderContext().error(
                     "Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
                     element, this.parseState.snapshot());
             return null;
         }
 }

AspectJMethodBeforeAdvice的bean定义信息

image-20241023115633817

3.1**解析<aop:pointcut**

 // ConfigBeanDefinitionParser
 private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
     String id = pointcutElement.getAttribute(ID);
     String expression = pointcutElement.getAttribute(EXPRESSION);
 ​
     AbstractBeanDefinition pointcutDefinition = null;
 ​
     try {
         this.parseState.push(new PointcutEntry(id));
         // AspectJExpressionPointcut
         pointcutDefinition = createPointcutDefinition(expression);
         pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
 ​
         String pointcutBeanName = id;
         if (StringUtils.hasText(pointcutBeanName)) {
             // 注册到容器
             parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
         } else {
             pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
         }
 ​
         parserContext.registerComponent(
                 new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
     }
     finally {
         this.parseState.pop();
     }
 ​
     return pointcutDefinition;
 }

<aop:config> 解析结束后beanDefinitionMap新增的bean定义信息:

image-20241023135406778

3、总结:

3.1流程图

3.2流程说明

3.2.1 <aop:aspectj-autoproxy/> 标签的解析

  • 作用:这个标签的作用是开启Spring AOP的自动代理功能。Spring在启动时,会通过AOP代理机制自动检测容器中的切面(Aspect)并为符合条件的Bean生成代理对象。

  • 关键类

    • AspectJAutoProxyBeanDefinitionParser:这是解析<aop:aspectj-autoproxy/>标签的解析器类。它的parse方法会创建并注册一个**AnnotationAwareAspectJAutoProxyCreator**。
    • AnnotationAwareAspectJAutoProxyCreator:这是一个核心类,它实现了BeanPostProcessor,在Spring容器启动时,它会在Bean初始化前后拦截并为符合条件的Bean生成代理。
  • 解析过程

    • AspectJAutoProxyBeanDefinitionParser首先会将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中。
    • 这个类会作为一个BeanPostProcessor,在Spring创建Bean的过程中介入,检测是否有需要增强的Bean,并为其创建代理对象。

3.2.2 <aop:config><aop:aspect> 的解析

  • 作用<aop:config>用于配置AOP切面。它指定了一个切面myAspect以及该切面包含的增强逻辑(beforeWork方法)。pointcut-ref引用了具体的切入点,定义了在哪些连接点(Join Point)应用通知。

  • 关键类

    • AopNamespaceUtils:这个类会协助注册AOP相关的配置。
    • ConfigBeanDefinitionParser:解析<aop:config><aop:aspect>等标签的类,负责解析切面定义。
    • AspectComponentDefinition:用于在Spring容器中注册切面定义。
  • 解析过程

    • ConfigBeanDefinitionParser会解析<aop:config>标签,并为每个<aop:aspect>生成对应的**Advisor**。这个Advisor会绑定切入点和通知,并注册到Spring容器中。
    • 在解析<aop:aspect>时,Spring会创建一个AspectJAdvisorFactory实例,负责将MyAspect的通知(beforeWork方法)与切点绑定。
    • aop:before标签会被解析为一个MethodBeforeAdvice,这个类在目标方法执行前执行增强逻辑。
    • aop:pointcut会生成一个Pointcut对象,包含匹配Work.doWork()方法的表达式信息。
    • 最终,Spring将生成的Advisor与切点、通知一起存储在Spring的AOP配置中。

3.2.3 <aop:pointcut> 的解析

  • 作用:定义切点表达式。这里指定public void com.lazy.snail.aop.Work.doWork()作为切点,表示在Work类的doWork()方法上应用通知。

  • 关键类

    • AspectJExpressionPointcut: 用于解析和保存AspectJ的切点表达式。
  • 解析过程

    • ConfigBeanDefinitionParser会将aop:pointcut标签解析为一个AspectJExpressionPointcut对象,解析表达式并保存切点匹配的逻辑。