Spring AOP之我若为王

简介: Spring AOP之我若为王

1FWhat is AspectJ?


说到AOP框架我们就不得不探讨一下AspectJ了,在Spring 开始支持AOP之初,也是大量借鉴了AspectJ的思想与编写习惯,在语法方面则完全借鉴了AspectJ,所以AspectJ对于Spring AOP的影响可以说非常巨大。但实际上,Spring AOP与AspectJ使用了完全不同的技术来实现切面框架。Spring AOP通过代理(JDKCGLIB)模型,采用动态织入技术,在内存中临时生成AOP代理类,因此也被称为运行时增强;而AspectJ则通过编译器在class字节码级别实现了静态织入的技术,也称为编译时增强。采用不同的技术,当然会有各自的利弊,采用动态织入技术不需要特殊编译器的支持,更符合项目级别的模块解耦,但是Spring AOP的切面必须基于Spring Beans进行切面,也就是说普通Java对象(POJO),无法通过Spring AOP建立切面;而AspecJ却没有这样的限制,可以在任意Java对象上建立切面。本节我们主要探讨一下AspectJ静态织入技术与原理。


2F静态织入


静态织入,即指Java代码在编译时期就将切面代码织入的技术,需要特殊编译器的支持。这里我们实践出真知,来看看究竟ApectJ的静态织入的到底是什么东东。为了方便,作者这里直接使用AspectJ项目支持的Eclipse扩展插件AJDT(Eclipse官网下载)来构建工程(AJDT只是AspectJ为了方便项目开发,将AspectJ编译器、语法提示集成在了插件中,读者也可以直接基于AspectJ命令行ajc进行编译,或者基于maven的工程项目可以使用aspectj-maven-plugin插件编译)。安装好AJDT插件后,就可以在Eclipse中建立一个AJDT类型的项目了,这里我们建立一个AspecJ示例工程:

image.png

新建项目之后,我们直接对main函数进行增强处理,AspectJ的开发与Spring AOP的advice开发方法稍有不同,但基本上还是java代码,只是代码文件的后缀名需要以 .aj作为后缀名(否则AspectJ编译器将不会进行增强处理):

image.png

增强代码(advice)就可以写在 *.aj 文件中进行编写了,下图是对于main函数的before与after增强的逻辑:

image.png

首先,需要注意增强处理类并没有使用class关键字,而是用了aspect关键字作为类的声明,并且切面表达式语法与Spring AOP中的使用语法也完全相同(Spring AOP与AspectJ切面语法保持了一致),其他的语法想必小伙伴们扫一眼就看明白了,这里就不累述了,我们运行工程,结果如下:

image.png

不出所料,对于main函数切点的增强处理正确的执行了。细心的小伙伴在这里应该会有疑问,Spring AOP切面框架不是无法对于staticfinal类型函数进行切面吗?的确如此,但是AspectJ却没有这方面限制,这也是AspectJ基于字节码技术的优势。


3F静态织入原理


关于AOP框架,相信很多小伙伴,都听过很多遍静态织入与动态织入了,但是却不明白到底什么是静态织入,或者说AspectJ是如何静态织入的?其实实现很复杂,但是原理很简单,静态织入就是将advice代码编译入切点处。这里,我们通过反编译工具JD-GUI来看一下AspectJ在上面示例是如何将beforeafter增强处理静态织入的,反编译.class结果如下:

image.png

通过反编译Main.class就可以看到,在main函数入口处与函数返回时,分别调用了before与after的增强逻辑,也就是说ApectJ将我们的增强处理以调用的方式编译进了切入点出,这就是静态织入实质,我们再来看一下增强代码的编译结果:

image.png

可以发现,实际上AspectJ实际上将源码中aspect关键字声明的类编译成了一个正常的java类,并且在增强声明中,采用了AspectJ注解方式来进行增强声明。AspectJ基于字节码级别的织入技术,使得其切面几乎可以关注任何Java对象生名周期的任何时期,因此非常强大。


4F动态代理原理


AspectJ虽然强大,但是Spring AOP的切面却是基于JDKCGLIB动态代理技术实现的,所以想要了解Spring AOP的核心原理还是需要先研究一下动态代理技术,关于JDKCGLIB的具体原理作者将会在下篇Spring AOP之代理之争一文中深挖,这里我们意在动态代理与静态织入的比较。这里,我们来看JDK是如何实现对象代理。

这里我们通过JDK代理对Spring AOP之初探黄龙一文中的WorkService类进行代理,并且添加beforeafter增强,使用JDK 代理需要我们实现InvocationHandler类来进行代理行为的控制,如下所示:

image.png

此时,我们就能使用ServiceProxyInvocationHandler来对Java对象进行代理了,并且在ServiceProxyInvocationHandler中,我们添加了类似切面的BeforeAfter增强处理。OK,现在我们使用ServiceProxyInvocationHandler来对WorkerSerivce对象进行代理:

image.png

运行结果可以发现,通过JDK代理技术的增强处理也被正确的执行了。其实,Spring AOP框架的核心原理也是通过使用InvocationHandlerProxy这两个类来实现对Spring Beans代理的。JDK代理使用起来尽然如此简单,但实际上JDK代理框架在背后做了很多手脚,会将根据代理的对象生成专门的代理类,为了便于深挖,我们将JDK代理生成的代理类保存到磁盘上来分析(默认动态代理直接在内存中生成,并通过Java类加载机制加载):

image.png

运行示例程序后会在项目的com.sum.proxy目录下会生成$Proxy0.class,二话不说,反编译它!

image.png

通过反编译,可以看到JDK代理生成的$Proxy0.class实际上是一个实现了IWorkService接口的子类,也就是说动态代理实际是通过接口生成增强过后的子类(CGLIB直接对代理对象继承)来实现的,因此代理是基于继承机制的,这也是Spring AOP框架无法对static与final进行切面的原因,由于不支持重写。

5F小结


面对AspectJSpring AOP项目中到底应该选择哪个框架?这要看项目中具体需要的增强需求了,如果本项目是基于Spring构建的项目,并且要增强的对象也都是Spring Beans,那么Spring AOP无疑是最好的选择。但如果项目比较老,并且需要对任意POJO都添加切面支持,那就只有AspectJ框架了。Java生态发展到今天,可以说已经很难离开Spring框架的依赖了(这句话没毛病吧?),所以Spring AOP也被广泛的应用在了很多Java组件中。本文并没有详细深挖动态织入技术,意在向小伙伴们分析静态织入的原理和展示动态与静态织入的具体区别,至于动态代理的详细分析,将会在Spring AOP系列的下一篇文章“Spirng AOP之代理之争”中深入讨论,敬请期待。


相关文章
|
2月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
412 0
|
1月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
6月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
1071 13
|
3月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
3月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
10月前
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
527 6
|
9月前
|
XML Java 测试技术
Spring AOP—通知类型 和 切入点表达式 万字详解(通俗易懂)
Spring 第五节 AOP——切入点表达式 万字详解!
669 25
|
9月前
|
XML 安全 Java
Spring AOP—深入动态代理 万字详解(通俗易懂)
Spring 第四节 AOP——动态代理 万字详解!
437 24
|
8月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
1029 0

热门文章

最新文章