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之代理之争”中深入讨论,敬请期待。


相关文章
|
5天前
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
|
14天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
57 8
|
2月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
96 5
|
2月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
91 8
|
2月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
53 5
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
59 4
|
3月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
62 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
2月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
51 1