Salmon的全栈知识 Salmon的全栈知识
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • SpringCloud Gateway
  • Apollo
  • Eureka
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • SpringCloud Gateway
  • Apollo
  • Eureka
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Spring框架

    • 传统Javaweb开发的困惑
    • IoC、DI和AOP思想提出
    • Spring框架的诞生
    • 基于xml的Spring应用
    • 基于注解的Spring应用
    • AOP 简介
    • 基于xml配置的AOP
    • 基于注解配置的AOP
      • 1、注解方式AOP基本使用
      • 2、注解方式AOP配置详解
      • 3、注解方式AOP原理剖析
    • 基于AOP的声明式事务控制
  • SpringMVC框架

    • Spring整合web环境
    • web层MVC框架思想与设计思路
    • SpringMVC简介
    • SpringMVC的请求处理
    • SpringMVC的响应处理
    • SpringMVC的拦截器
    • SpringMVC的全注解开发
    • SpringMVC的组件原理剖析
    • SpringMVC的异常处理机制
  • 《Spring生态》笔记
  • Spring框架
Salmon
2025-07-23
目录

基于注解配置的AOP

# 1、注解方式AOP基本使用

Spring的AOP也提供了注解方式配置,使用相应的注解替代之前的xml配置,xml配置AOP时,我们主要配置了三部分:目标类被Spring容器管理、通知类被Spring管理、通知与切点的织入(切面),如下:

<!-- 配置目标对象 -->
<bean id="target" class="com.itheima.aop.TargetImpl" />

<!-- 配置通知对象 -->
<bean id="advices" class="com.itheima.aop.Advices" />

<!-- 配置 AOP 切面 -->
<aop:config proxy-target-class="true">
    <!-- 声明一个切面,引用通知对象 -->
    <aop:aspect ref="advices">
        <!-- 配置环绕通知 -->
        <aop:around 
            method="around" 
            pointcut="execution(* com.itheima.aop.*.*(..))" />
    </aop:aspect>
</aop:config>

目标类被Spring容器管理、通知类被Spring管理

// 目标类,实现了 Target 接口
@Component("target")
public class TargetImpl implements Target {

    @Override
    public void show() {
        System.out.println("show Target running...");
    }
}

// 通知类,包含一个环绕通知方法
@Component
public class AnnoAdvice {

    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前通知...");
        
        // 调用目标方法
        joinPoint.proceed();
        
        System.out.println("环绕后通知...");
    }
}

配置aop,其实配置aop主要就是配置通知类中的哪个方法(通知类型)对应的切点表达式是什么

image-20250725150529247

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

// 第一步:声明该类是一个切面组件
@Component
@Aspect
public class AnnoAdvice {

    // 第二步:定义环绕通知,拦截 com.itheima.aop 包下所有方法
    @Around("execution(* com.itheima.aop.*.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前通知...");
        
        // 执行目标方法
        joinPoint.proceed();
        
        System.out.println("环绕后通知...");
    }
}

注解@Aspect、@Around需要被Spring解析,所以在Spring核心配置文件中需要配置aspectj的自动代理

<aop:aspectj-autoproxy/>

如果核心配置使用的是配置类的话,需要配置注解方式的aop自动代理

@Configuration
@ComponentScan("com.itheima.aop")
@EnableAspectJAutoProxy //第三步
public class ApplicationContextConfig {
}

# 2、注解方式AOP配置详解

各种注解方式通知类型

//前置通知
@Before("execution(* com.itheima.aop.*.*(..))")
public void before(JoinPoint joinPoint){}
//后置通知
@AfterReturning("execution(* com.itheima.aop.*.*(..))")
public void AfterReturning(JoinPoint joinPoint){}
//环绕通知
@Around("execution(* com.itheima.aop.*.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {}
//异常通知
@AfterThrowing("execution(* com.itheima.aop.*.*(..))")
public void AfterThrowing(JoinPoint joinPoint){}
//最终通知
@After("execution(* com.itheima.aop.*.*(..))")
public void After(JoinPoint joinPoint){}

切点表达式的抽取,使用一个空方法,将切点表达式标注在空方法上,其他通知方法引用即可

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AnnoAdvice {

    // 切点表达式抽取:匹配 com.itheima.aop 包下的所有方法
    @Pointcut("execution(* com.itheima.aop.*.*(..))")
    public void pointcut() {}

    // 前置通知:在目标方法执行前执行
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("前置通知...");
        // 可使用 joinPoint.getSignature() 获取方法签名信息
    }

    // 后置通知:在目标方法正常返回后执行(不包括抛异常)
    @AfterReturning("AnnoAdvice.pointcut()")
    public void afterReturning(JoinPoint joinPoint) {
        System.out.println("后置通知...");
    }

    // 其他通知可继续添加,例如 @After、@AfterThrowing、@Around 等
}

# 3、注解方式AOP原理剖析

之前在使用xml配置AOP时,是借助的Spring的外部命名空间的加载方式完成的,使用注解配置后,就抛弃了 <aop:config>标签,而该标签最终加载了名为AspectJAwareAdvisorAutoProxyCreator的BeanPostProcessor ,最终,在该BeanPostProcessor中完成了代理对象的生成。

同样,从aspectj-autoproxy标签的解析器入手

this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

之前在使用xml配置AOP时,是借助的Spring的外部命名空间的加载方式完成的,使用注解配置后,就抛弃了<aop:config>标签,而该标签最终加载了名为AspectJAwareAdvisorAutoProxyCreator的BeanPostProcessor ,最终,在该BeanPostProcessor中完成了代理对象的生成。

<!--开启aop aspectj的自动代理-->
<aop:aspectj-autoproxy/>

同样,从aspectj-autoproxy标签的解析器入手

this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

而AspectJAutoProxyBeanDefinitionParser代码内部,最终也是执行了和xml方式AOP一样的代码

registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source)

如果使用的是核心配置类的话

@Configuration
@ComponentScan("com.itheima.aop")
@EnableAspectJAutoProxy
public class ApplicationContextConfig {
}

查看@EnableAspectJAutoProxy源码,使用的也是@Import导入相关解析类

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
	boolean proxyTargetClass() default false;
	boolean exposeProxy() default false;
}

使用@Import导入的AspectJAutoProxyRegistrar源码,一路追踪下去,最终还是注册了AnnotationAwareAspectJAutoProxyCreator 这个类

// 方法 1:AOP 导入类中触发注册自动代理创建器
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, 
                                     BeanDefinitionRegistry registry) {
    // 注册 AspectJ 注解自动代理创建器
    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}

// 方法 2:重载方法,提供默认的 source 参数为 null
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

// 方法 3:最终调用注册或升级自动代理创建器
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, 
                                                                                   @Nullable Object source) {
    // 注册或升级 AnnotationAwareAspectJAutoProxyCreator 到容器中
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

image-20250725151057493

上次更新: 2025/07/25, 07:39:11
基于xml配置的AOP
基于AOP的声明式事务控制

← 基于xml配置的AOP 基于AOP的声明式事务控制→

Theme by Vdoing | Copyright © 2022-2025 Salmon's Blog
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式