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


相关文章
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
11天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
1月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
37 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
16天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
27 1
|
12天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
25 0
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
1月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
72 2
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
127 9
|
1月前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
45 0
|
2月前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理