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


相关文章
|
1月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
1天前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
2月前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
15天前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
1月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
28天前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
22 0
Spring高手之路22——AOP切面类的封装与解析
|
1月前
|
安全 Java 开发者
Java 新手入门:Spring 两大利器IoC 和 AOP,小白也能轻松理解!
Java 新手入门:Spring 两大利器IoC 和 AOP,小白也能轻松理解!
31 1
|
1月前
|
Java Spring
Spring的AOP组件详解
该文章主要介绍了Spring AOP(面向切面编程)组件的实现原理,包括Spring AOP的基础概念、动态代理模式、AOP组件的实现以及Spring选择JDK动态代理或CGLIB动态代理的依据。
Spring的AOP组件详解
|
1月前
|
Java API Spring
Spring Boot 中的 AOP 处理
对 Spring Boot 中的切面 AOP 做了详细的讲解,主要介绍了 Spring Boot 中 AOP 的引入,常用注解的使用,参数的使用,以及常用 api 的介绍。AOP 在实际项目中很有用,对切面方法执行前后都可以根据具体的业务,做相应的预处理或者增强处理,同时也可以用作异常捕获处理,可以根据具体业务场景,合理去使用 AOP。
|
28天前
|
Java Spring XML
掌握面向切面编程的秘密武器:Spring AOP 让你的代码优雅转身,横切关注点再也不是难题!
【8月更文挑战第31天】面向切面编程(AOP)通过切面封装横切关注点,如日志记录、事务管理等,使业务逻辑更清晰。Spring AOP提供强大工具,无需在业务代码中硬编码这些功能。本文将深入探讨Spring AOP的概念、工作原理及实际应用,展示如何通过基于注解的配置创建切面,优化代码结构并提高可维护性。通过示例说明如何定义切面类、通知方法及其应用时机,实现方法调用前后的日志记录,展示AOP在分离关注点和添加新功能方面的优势。
36 0