[!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支持以下几种类型的通知:- 前置通知(Before Advice):在目标方法执行之前运行的通知。
- 后置通知(After Advice):在目标方法执行之后运行的通知,且无论方法是否成功执行都会执行。
- 返回通知(After Returning Advice):目标方法成功执行并返回结果之后运行的通知。
- 异常通知(After Throwing Advice):目标方法抛出异常时运行的通知。
- 环绕通知(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
Advisor
- Advisor是Spring AOP中一个更高层次的概念,它是通知(Advice)和切点(Pointcut)的结合。可以认为它是一个带有条件的通知。
- 一个Advisor包含了一个通知和一个切点,用来定义在特定的切入点上应该执行哪个通知。例如,某个Advisor可能指定在调用某个类的特定方法时执行前置通知。
- 在Spring中,
org.springframework.aop.Advisor
接口用于定义这种结构。常见的Advisor
有DefaultPointcutAdvisor
,它允许你为某个切点绑定一个具体的通知。
Advised
- Advised是Spring AOP框架中一个被增强(advised)对象的抽象接口。这个接口允许对目标对象应用不同的增强逻辑(advice),并通过代理对象执行这些增强操作。
- 在Spring中,
org.springframework.aop.framework.Advised
接口提供了管理增强和代理的能力。它允许开发者动态地增加或删除通知、控制代理行为等。
1.1.3Spring AOP 和 AspectJ
Spring AOP
- 代理机制:Spring AOP是基于动态代理的实现,使用JDK动态代理或CGLIB字节码生成来创建代理对象。它只支持方法级别的AOP,无法像AspectJ那样拦截字段、构造函数等其他结构。
- 织入方式:Spring AOP属于运行时织入,代理对象在运行时生成,适合于大多数基于Spring的项目。
- 易用性:Spring AOP集成在Spring框架中,使用起来更加简洁灵活,特别适合面向Spring Bean的AOP需求。
AspectJ
- 编译时增强:AspectJ是一种静态编译时AOP框架,它不仅可以拦截方法,还可以拦截字段、构造函数等。AspectJ通过字节码修改的方式实现织入,增强代码在编译时(或类加载时)已经被注入到目标对象中,称为编译时织入或类加载时织入。
- 强大灵活:AspectJ的切点表达式更强大,它能够定义更复杂的匹配规则和拦截粒度,超越了Spring AOP的能力。
- 性能:由于AspectJ在编译时已经将增强逻辑注入到目标类中,执行时无需动态代理,因此它的性能相对较高。
- 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());
}
下面的解析过程实际就是往容器注册了一个名为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
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定义信息
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定义信息:
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
对象,解析表达式并保存切点匹配的逻辑。