手动实现AspectJ的编译前、编译后、加载时、加载后的实现方案。

本文深入解析AspectJ的织入技术,涵盖编译前、编译后、加载时及加载后的四个方面。详细介绍了如何使用ajc指令及自定义classloader实现切面的织入,同时提供了加载时和加载后的具体代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前提思想

研究AspectJ的实现,首先必须要明白一个大前提,那就是是其实对于jvm虚拟机来说,它只认符合class文件结构的文件,无论这个文件是从java语言还是AspectJ语言、或者其它什么语言编译的,最终,只要生成的文件符合class文件结构,就能被jvm所识别并加载。

同时,我们还要了解一个前提,那就是Aspectj织入功能,其实可以分别在四个阶段进行织入:

第一个阶段:编译前。所谓的编译前,就是我们可以使用ajc指令直接对.java文件进行织入,这一个阶段会生成新的class文件结构,并且会回写到磁盘上,替换原class文件。

第二个阶段:编译后。所谓的编译后,就是指的,我们可以使用ajc指令,直接对.class文件进行织入。这一个阶段会生成新的class文件结构,并且会回写到磁盘上,替换原class文件。

第三个阶段:加载时。所谓的加载时,就是在class文件被classloader加载时,我们可以通过特殊的技术手段,比如自己实现classloader或者使用Java SE 6 新特性新特性提供的Instrumentation 新功能来实现,这一个阶段会生成新的class文件结构,但是并不需要将新生成的文件写回到磁盘上,主要此时新生成的class文件结构也完全不同于上面的两种,内容太深,如果想细究,可在后面将二进制流打印出来,并使用javap反编译看一下(只有用javaP反编译才能看出来)。

第四个阶段:加载后。所谓的加载后,就是指class文件已经被jvm加载,我们通过jdk6新特性提供的Instrumentation 新功能来实现对内存中的class文件强制替换的功能来实现,其实AspectJ官方并没有介绍这个阶段,因为这个阶段,aspectj主要提供的功能,还是像第三阶段一样,重构原class文件结构,生成新的class文件结构二进制流,而替换的工作主要是由Java SE 6 新特性新特性提供的Instrumentation 新功能来实现。

 

编译前、编译后的代码实现

该功能实现可以使用自定义的classloader来实现,也可以使用Java SE 6 新特性新特性提供的Instrumentation 新功能来实现,至于新特性实现我就不讲了,推荐看这篇文章(https://www.ibm.com/developerworks/cn/java/j-lo-jse61/index.html),我只讲如何将 切面织入编译前和编译后的代码中。

两种方式:

第一种,使用ajc指令,ajc指令其实就相当于java指令,我们可以使用

Runtime.getRuntime().exec(ajc指令)的方式来实现。

这里主要注意两点:

第一:使用Runtime.getRuntime().exec执行ajc指令,需要在ajc指令前加上cmd /c;

第二点:ajc指令的核心几个要素,

-classpath:要在路径下指定aspectjrt的jar包
-aspectpath:在该要素下指定切面所在路径。
-inpath:在该要素下,指定想要被切面修饰的类。

第二种,调用ajc的代码方式实现:

Main main = new Main();
MessageHandler messageHandler=new MessageHandler();
main.run(args,messageHandler);

这里的args是一个数组,其实就是将前面所讲的ajc指令的核心要素,一个个分成数组的元素,另外该方法执行需要指定一个指令要素

-cp:该要素指定java运行环境所需的jar包路径。

 

加载时和加载后的代码实现

同样推荐先看推荐看这篇文章(https://www.ibm.com/developerworks/cn/java/j-lo-jse61/index.html)这篇文章,了解如何在加载前和加载后实现java的class对象拦截。

加载时和加载后的代码后的代码织入则要求有如下格式:

 

第一个,在Meta-INF里建一个Aop的xml文件(文件怎么建‘以及文件作用请参考https://www.eclipse.org/aspectj/doc/released/devguide/ltw-configuration.html

第二步,使用Aj对象,对代码进行重新织入,核心代码如下三行:

Aj aj=new Aj();
aj.initialize();
byte[] bytes1=aj.preProcess(className,bytes,this.getClass().getClassLoader(),null);

Aj对象是AspectJ提供的,preProcess的几个参数分别如下:

className:被修饰对象的类名,该类名必须是译\或/来修饰的,比如com/alibaba/test/Test这样的

bytes:被修饰对象的字节流。

this.getClass().getClassLoader():很容易看明白。

bytes1:就是使用Aspectj织入代码后的二进制流了。

 

整个工作的核心代码,至此讲完。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值