首页 > 其他分享 >聊一聊Spring中的AOP【XML】【标签解析】

聊一聊Spring中的AOP【XML】【标签解析】

时间:2024-10-23 20:47:28浏览次数:3  
标签:XML parserContext Spring 切点 element AOP new

[!NOTE]

**Spring版本:**5.3.27

**AspectJ版本:**1.9.22

**JDK版本:**1.8

1、前置说明

[!TIP]

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

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

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>

[!NOTE]

<!-- 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对象,解析表达式并保存切点匹配的逻辑。

标签:XML,parserContext,Spring,切点,element,AOP,new
From: https://blog.csdn.net/indolentSnail/article/details/143185940

相关文章

  • 毕业设计-基于SpringBoot与Vue实现的智能停车场系统
    项目简介基于SpringBoot+Vue的智能停车场项目系统内置多项核心功能,包括系统管理、账号管理、系统监控、财务管理、停车记录、车辆管理、车牌识别和停车场管理。系统管理涵盖角色、接口、菜单和全局配置,账号管理包括用户和合作单位管理。系统监控提供监控大屏和日志监控功......
  • 毕业设计-基于springboot+vue实现的在线文档管理系统源码+论文
    项目简介这个在线文档管理系统基于MySQL数据库,并采用了SpringBoot框架进行开发。在设计过程中,我们特别注重了系统代码的可读性、实用性、易扩展性、通用性、维护便捷性以及页面简洁性等特点。当前,许多人仍然依赖传统的纸质工具来进行信息管理,而网络技术仅仅被视为辅助手段。......
  • Java Spring的常用注解详解和案例示范
    1.Spring常用注解概述1.1@Component@Component是Spring的基础注解之一,它用于将类标记为Spring容器中的一个组件。通过@Component注解,Spring会自动将该类注册为一个Bean,供依赖注入使用。使用示例:@ComponentpublicclassUserService{publicvoidperf......
  • Spring事务底层源码解析(二)
    今天根据具体的业务代码场景去分析spring事务的源码流程,其中事务传播属性还是PROPAGATION_REQUIRED首先看下第一种业务场景,testTransaction1方法上加了@Transactionl注解,注解中调用了insertTransactionOne(),insertTransactionTwo()方法,这两个方法上面也都加了@Transactionl注......
  • spring boot整合Swagger
    你可能尝试过写完一个接口后,自己去创建接口文档,或者修改接口后修改接口文档。多了之后,你肯定会发生一个操作,那就是忘记了修改文档或者创建文档(除非你们公司把接口文档和写接口要求得很紧密......
  • vue3+java基于Spring Boot的爱老助老服务平台源码 lw 部署
    目录功能介绍具体实现截图技术介绍开发核心技术介绍:技术创新点vue3和vue2的区别:核心代码部分展示非功能需求分析系统开发流程软件测试源码获取功能介绍爱老助老服务平台的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使......
  • Spring Boot 替换Word模板生成Word文件教程
    ......
  • springboot062购物推荐网站的设计与实现(论文+源码)_kaic
    东大每日推购物推荐网站的设计与实现摘要随着信息互联网购物的飞速发展,一般企业都去创建属于自己的电商平台以及购物管理系统。本文介绍了东大每日推购物推荐网站的开发全过程。通过分析企业对于东大每日推购物推荐网站的需求,创建了一个计算机管理东大每日推购物推荐网站的......
  • Springboot异步事件配置和使用
    Spring中提供了完整的事件处理机制,本身底层内置实现了一些事件和监听,同时支持开发者扩展自己的事件和监听实现。一般这种基于事件的实现在项目实际开发中我们主要用来解耦,和做异步处理(默认是同步),提供应用的响应速度。核心架构先简要看一下,在Spring中要实现自定义事件监听需要......
  • 第一个Java spring boot demo运行
     一、环境准备1,下载JavaJDK需要安装两个JDK版本:1.8/17安装ZuluJDK(不能使用OracleJDK)JDK17:https://www.azul.com/downloads/?version=java-17-lts&os=macos&package=jdk#zuluJDK8:https://www.azul.com/downloads/?version=java-8-lts&os=macos&package=jdk#zul......