什么是AOP,如何实现?(有落地代码)

news2025/1/10 1:48:21

AOP 的核心思想是将横切关注点抽象为一个独立的模块(称之为“切面”),然后在需要应用它的地方进行调用。比如,在需要记录日志的方法中,我们可以定义一个切面来负责日志记录,这样所有调用该方法的地方都会被自动添加上日志功能,而不必修改原有方法。AOP 通过使用诸如“切点”、“连接点”、“通知”等概念,使得开发人员可以灵活地控制切面的应用范围和时机。

AOP 的常用实现方式是利用代理对象来实现切面功能。在 Java 领域中,常见的 AOP 框架有 Spring AOP 和 AspectJ 等。除了 Java,AOP 的思想还可以应用于其它编程语言和平台。

Spring AOP 和 AspectJ AOP

Spring AOP 和 AspectJ AOP 是两种不同的 AOP 实现。Spring AOP 基于动态代理实现,是 Spring 框架中的 AOP 实现,主要用于解决 Spring 容器中 Bean 的横切关注点问题。由于使用了动态代理,所以只支持方法级别的切面(即只能织入方法的执行)。尽管 Spring AOP 的性能略逊于 AspectJ,但对于大部分应用来说,性能影响不大。

相比之下,AspectJ AOP 是一个独立的、功能更强大的 AOP 实现。它不仅支持方法级别的切面,还支持字段、构造器等其他切面,并可通过编译时织入或加载时织入的方式实现 AOP。这使得 AspectJ 比 Spring AOP 更加灵活和强大。同时,Spring 可以与 AspectJ 结合使用,以提供更强大的 AOP 功能。

实现 AOP 的方式

动态代理:通过代理模式,为目标对象生成一个代理对象,然后在代理对象中实现横切关注点的织入。动态代理可以分为JDK动态代理(基于接口)和 CGLIB 动态代理(基于类)。

编译时织入:在编译阶段,通过修改字节码实现 AOP。AspectJ 的编译时织入就是这种方式。

类加载时织入:在类加载阶段,通过修改字节码实现 AOP。AspectJ 的加载时织入就是这种方式。

AOP的实现方式取决于具体需求和技术选型。对于 Spring 应用来说,通常可以使用 Spring AOP 满足大部分需求,如果需要更强大的 AOP 功能,可以考虑使用 AspectJ。

AOP 的相关概念

实战1

使用spring的AOP,实现日志切面,打印每次方法的入参和返回。

首先,我们需要在Spring配置文件中启用AOP:

<beans>
    <aop:aspectj-autoproxy />
    <!-- 其他配置 -->
</beans>

然后,我们可以创建一个切面类来实现日志记录:

@Aspect
@Component
public class LoggingAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingAspect.class);

    @Pointcut("execution(* com.example.*.*(..))")
    public void logMethod() {}

    @Before("logMethod()")
    public void logMethodEntry(JoinPoint joinPoint) {
        LOGGER.info("Entering method: {} with arguments: {}", joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(pointcut = "logMethod()", returning = "result")
    public void logMethodExit(JoinPoint joinPoint, Object result) {
        LOGGER.info("Exiting method: {} with result: {}", joinPoint.getSignature().getName(), result);
    }
}

在上面的代码中,我们定义了一个切点 logMethod(),它匹配所有 com.example 包下的方法。然后,我们使用 @Before@AfterReturning 注解来分别记录方法的入参和返回值。在 JoinPoint 对象中,我们可以获取方法的签名和参数。

最后,我们可以在需要记录日志的方法上添加 @LogMethod 注解来启用日志切面:

@Service
public class MyService {

    @LogMethod
    public void doSomething(String arg1, int arg2) {
        // 方法实现
    }
}

这样,每次调用 doSomething 方法时,日志切面都会记录方法的入参和返回值。

对于 Spring Boot 项目,实现日志切面的方法与普通的 Spring 项目类似。只需要在 Spring Boot 的配置类上添加 @EnableAspectJAutoProxy 注解即可启用 AOP。

下面是一个示例:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    // 其他配置
}

然后,我们可以创建一个切面类来实现日志记录:

@Aspect
@Component
public class LoggingAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingAspect.class);

    @Pointcut("execution(* com.example.*.*(..))")
    public void logMethod() {}

    @Before("logMethod()")
    public void logMethodEntry(JoinPoint joinPoint) {
        LOGGER.info("Entering method: {} with arguments: {}", joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(pointcut = "logMethod()", returning = "result")
    public void logMethodExit(JoinPoint joinPoint, Object result) {
        LOGGER.info("Exiting method: {} with result: {}", joinPoint.getSignature().getName(), result);
    }
}

在上面的代码中,我们定义了一个切点 logMethod(),它匹配所有 com.example 包下的方法。然后,我们使用 @Before@AfterReturning 注解来分别记录方法的入参和返回值。在 JoinPoint 对象中,我们可以获取方法的签名和参数。

最后,我们可以在需要记录日志的方法上添加 @LogMethod 注解用日志:

@Service
public class MyService {

    @LogMethod
    public void doSomething(String arg1, int arg2) {
        // 方法实现
    }
}

这样,每次调用 doSomething 方法时,日志切面都会记录方法的入参和返回值。

实战2

使用AspectJ AOP,实现日志切面,打印每次方法的入参和返回。

使用 AspectJ AOP 结合 Spring Boot 也是非常简单的。下面是一个示例:

首先,我们需要在 pom.xml 文件中添加 AspectJ 相关的依赖:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.6</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

然后,我们可以创建一个切面类来实现日志记录:

@Aspect
@Component
public class LoggingAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingAspect.class);

    @Pointcut("execution(* com.example.*.*(..))")
    public void logMethod() {}

    @Before("logMethod()")
    public void logMethodEntry(JoinPoint joinPoint) {
        LOGGER.info("Entering method: {} with arguments: {}", joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
    }

    @(pointcut = "logMethod()", returning = "result")
    public void logMethodExit(JoinPoint joinPoint, Object result) {
        LOGGER.info("Exiting method: {} with result: {}", joinPoint.getSignature().getName(), result);
    }
}

在上面的代码中,我们定义了一个切点 logMethod(),它匹配所有 com.example 包下的方法。然后,我们使用 @Before@AfterReturning 注解来分别记录方法的入参和返回值。在 JoinPoint 对象中,我们可以获取方法的签名和参数。

最后,我们需要在 Spring Boot 的配置类上添加 @EnableAspectJAutoProxy 注解来启用 AspectJ AOP:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    // 其他配置
}

这样,我们就可以在需要记录日志的方法上添加 @LogMethod 注解用日志:

@Service
public class MyService {

    @LogMethod
    public void doSomething(String arg1, int arg2) {
        // 方法实现
    }
}

这样,每次调用 doSomething 方法时,日志切面都会记录方法的入参和返回值。

总结

好的,下面是 AOP 的总结:

AOP(Aspect-Oriented Programming)是一种编程范式,它通过将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,以模块化的方式实现这些关注点。AOP 的核心思想是将程序的功能分解成不同的关注点,然后通过切面将这些关注点模块化,从而提高代码的可维护性和可重用性。

AOP 的主要概念包括:

  • 切面(Aspect):横切关注点的模块化,它包括切点和通知。

  • 切点(Pointcut):程序中需要被拦截的方法或者类。

  • 通知(Advice):在切点处执行的代码,包括前置通知、后置通知、异常通知、最终通知和环绕通知。

  • 连接点(Join Point):程序中可以被拦截的点,通常是方法调用或者异常处理等。

  • 织入(Weaving):将切面应用到目标对象并创建新的代理对象的过程。

AOP 的实现方式包括:

  • 静态代理:手动编写代理类,将切面代码硬编码到代理类中。

  • 动态代理:使用 JDK 动态代理或者 CGLIB 动态代理生成代理对象,将切面代码动态织入到代理对象中。

  • AspectJ:一种基于 Java 语言的 AOP 框架,它提供了更加灵活和强大的 AOP 功能,支持编译时织入和运行时织入两种方式。

AOP 的优点包括:

  • 提高代码的可维护性和可重用性,将横切关注点从业务逻辑中分离出来,使得代码更加模块化。

  • 降低代码的耦合度,将不同的关注点分离开来,使得代码更加灵活和可扩展。

  • 提高代码的可读性和可理解性,将关注点的代码集中在一起,使得代码更加清晰和易于理解。

AOP 的缺点包括:

  • 增加了代码的复杂度,需要额外的学习和理解成本。

  • 可能会影响程序的性能,特别是在运行时织入切面时,会增加额外的开销。

  • 可能会导致调试和排错变得更加困难,特别是在切面代码中存在错误时,可能会影响整个程序的运行。

     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/567801.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hugging face开源的transformers模型可快速搭建图片分类任务

2017年,谷歌团队在论文「Attention Is All You Need」提出了创新模型,其应用于NLP领域架构Transformer模型。从模型发布至今,transformer模型风靡微软、谷歌、Meta等大型科技公司。且目前有模型大一统的趋势,现在transformer 模型不仅风靡整个NLP领域,且随着VIT SWIN等变体…

关于I/O

I/O 1. 概念1.1 页缓存的简单工作流程1.2 页缓存的写机制或者写触发的时机1.3 为什么需要套字节缓冲区1.4 套接字缓冲区的简单流程 2. 传统I/O方式2.1 传统I/O读写流程2.2 传统 I/O的性能问题 3. DMA技术3.1 将数据写入磁盘的流程3.2 从磁盘读取数据的流程 4. 网络数据传输流程…

【python】制作一个点单小程序!

周末总是在吃的方面&#xff0c;及其纠结&#xff0c;今天来制作一个点单小程序&#xff0c;加入自己喜欢吃的东西&#xff0c;来慢慢挑选&#xff0c;让每个周末快乐无限&#xff01; 一.安装环境 python 3.7.8 QT xlrd、xlwt库使用pip接口进行安装 pip install xlrd pip …

DMBOK知识梳理for CDGA/CDGP——第一章数据管理

关 注gzh“大数据食铁兽“&#xff0c;回复“知识点”获取《DMBOK知识梳理for CDGA/CDGP》常考知识点&#xff08;第一章数据管理&#xff09; 第一章 数据管理 第一章在 CDGA|CDGP考试中分值占比均不是很高&#xff0c;主要侧重点是考概念性的知识&#xff0c;理解数据管理的…

设计模式 -第1部分 避免浪费- 第1章 Flyweight 模式 - 共享对象避免浪费

第1部分 避免浪费 注&#xff1a;其内容主要来自于【日】-结城浩 著《图解设计模式》20章节 极力推荐大家阅读原著 第1章 Flyweight 模式 - 共享对象避免浪费 1.1 Flyweight 模式 Flyweight 的意思"轻量级"&#xff0c;其在英文中的原意指比赛中选手体重最轻等级的一…

迪赛智慧数——饼图柱状图(基本饼图和基本柱状图):“怒路症”数据解读

效果图 35%的司机承认自己属于“路怒族”&#xff0c;还有65%的人表示自己不是“路怒族”。 近日&#xff0c;上海两车高架上斗气碰撞差点掉落高架&#xff0c;上海高架出现“史诗级”斗气车。小编在此呼吁大家&#xff0c;开车路上减压&#xff0c;避免坏情绪伴随&#xff0c…

DDoS攻击与防御(一)

前言 这章主要讲述DDoS攻击与防御方式 理论知识来源于 https://www.microsoft.com/zh-cn/security/business/security-101/what-is-a-ddos-attack 1&#xff1a;攻击 一般来说&#xff0c;DDoS 攻击分为三大类&#xff1a;容量耗尽攻击、协议攻击和资源层攻击。 1>容量耗尽…

shiro基于redis实现分布式权限管理,在加入shiro的缓存管理后,项目报错

shiro基于redis实现分布式权限管理&#xff0c;在加入shiro的缓存管理后&#xff0c;项目报错 报错信息概括解决其他详细报错信息 报错信息概括 2023-05-24 16:27:56.374 ERROR 28740 --- [nio-8092-exec-6] o.a.s.web.servlet.AbstractShiroFilter : session.touch() method …

水处理计算常用表格大全

第二章 设计方案城市污水处理厂的设计规模与进入处理厂的污水水质和水量有关&#xff0c;污水的水质和水量可以通过设计任务书的原始资料计算。2.1 厂址选择在污水处理厂设计中&#xff0c;选定厂址是一个重要的环节&#xff0c;处理广的位置对周围环境卫生、基建投资及运行管理…

加强密码安全,保护您的账户——ADSelfService Plus

在当今数字化时代&#xff0c;密码安全成为了每个人都需要关注的重要问题。随着越来越多的个人和组织依赖于互联网和电子系统进行业务和通信&#xff0c;确保账户的安全性变得尤为关键。在这方面&#xff0c;ADSelfService Plus是一个功能强大的解决方案&#xff0c;为用户提供…

版图设计工具解析-virtuoso的display.drf文件解析

1. display.drf文件解析 virtuoso的版图颜色定义分析 下图为virtuoso的版图颜色&#xff0c;包括填充&#xff0c;轮廓&#xff0c;彩点&#xff0c;线形 本文以smic18mmrf的display.drf文件进行解析 smic18的PDK包下存在display.drf文件 打开文件display.drf文件后看到如下…

ApiKit 简介安装以及如何使用

一、介绍 ApiKit 是接口管理、开发、测试全流程集成工具&#xff0c;定位 API 管理 Mock 自动化测试 异常监控 团队协作。 1、开发测试过程中的现状 yapi -- 管理接口文档 rap -- 前端开发mock数据 postman -- 开发调试接口、测试调用接口 jmeter -- 基本的压力测试 2…

1个普通Java程序员需要具备什么样的素质和能力才可以称得上高级工程师?

1个Java程序员具备什么样的素质和能力才可以称得上高级工程师&#xff1f; 这个问题也引发了我的一些思考&#xff0c;可能很多人会说&#xff0c;“作为高级工程师&#xff0c;基础得过硬、得熟练掌握一门编程语言、至少看过一个优秀开源项目的源代码、有过高并发/性能优化的…

【RocketMQ】RocketMQ入门

【RocketMQ】RocketMQ入门 文章目录 【RocketMQ】RocketMQ入门1. 消费模式2. 发送/消费 消息2.1 同步消息2.2 异步消息2.3 单向消息2.4 延迟消息2.5 批量消息2.6 顺序消息 1. 消费模式 MQ的消费模式大致分为两种&#xff0c;一种是推Push&#xff0c;一种是拉pull。 Push模式…

在变压器厂中使用 ISA-95 应用程序进行调度集成

介绍 在工业批量和连续生产/运营环境中&#xff0c;调度涉及将诸如罐、反应器和其他加工设备之类的资源分配给生产/运营任务。第 4 层生产/运营计划确定要制造什么产品、要制造多少产品以及何时制造。根据设备、物料、人员和班次的可用性&#xff0c;随着时间的推移分配资源。…

CSDN中如何获得铁粉(用心篇)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

快速实现pytest自定义配置项,让Web自动化测试更便捷!

目录 前言&#xff1a; 一、什么是pytest.ini 二、在pytest.ini中添加自定义配置项 三、使用自定义配置项 四、结论 前言&#xff1a; WEB自动化测试是一个重要的环节&#xff0c;需要结合框架和工具进行开发。在WEB自动化测试中&#xff0c;常用的是pytest框架&#xff…

go sync包

官方文档&#xff1a;https://pkg.go.dev/sync 临界区 临界区(critical section)是指包含有共享数据的一段代码&#xff0c;这些代码可能被多个线程访问 或修改。临界区的存在就是为了保证当有一个线程在临界区内执行的时候&#xff0c;不能有其他任何线程被允许在临界区执行…

workquue

参考 讲解Linux内核工作队列workqueue源码分析 - 知乎 浅谈Linux内核中断下半部——工作队列&#xff08;work queue&#xff09; - 知乎 kernel/workqueue.c 初始化 /** 6004 * workqueue_init_early - early init for workqueue subsystem 6005 * 6006 * This is th…

字节测开5年经验之谈,1分钟了解自动化测试..

引子 写在最前面&#xff1a;目前自动化测试并不属于新鲜的事物&#xff0c;或者说自动化测试的各种方法论已经层出不穷&#xff0c;但是&#xff0c;能够明白自动化测试并很好落地实施的团队还不是非常多&#xff0c;我们接来下用通俗的方式来介绍自动化测试…… 本文共有2410…