如何阻止AspectJ重复织入并仅修改第三方二进制包中的单个类?
原有advice丢失的机制
你当前配置将第三方包放在inpath中时,iajc默认会对inpath内的所有类执行全量重织入流程:首先清除类中已有的AspectJ织入标记、原有advice生成的字节码,再基于当前加载的aspect集合重新执行织入。
由于你没有将第三方包中原本的aspect定义加入aspect路径,iajc重织入时无法识别原有aspect,仅会织入你本次指定的HelperAspect,原有advice自然会被清除。部分绑定到私有方法、类初始化切点的原有advice丢失概率更高,是因为这类切点的织入逻辑对原aspect定义的依赖更强,重织入时无对应aspect就会被完全清理。
阻止原有advice被移除的方案
你需要修改iajc配置,让iajc识别第三方包的原有aspect,避免全量清理原有织入逻辑:
- 增加
aspectPath配置,将原始第三方包加入aspect路径,让iajc可以读取包内的原有aspect定义,重织入时保留原有advice - 增加织入参数
-Xreweavable,开启字节码可重织入属性,避免iajc清理未修改类的原有织入逻辑 - 增加参数
-XpreserveAllAnnotations,保留类中所有AspectJ生成的标记注解
修改后的配置参考:
<iajc srcdir="../src" source="1.7" inpath="${build.web.lib}/thirdpartylibrary-original.jar" outjar="${build.web.lib}/thirdpartylibrary.jar" XlintFile="../src/com/company/utility/helperAspect/ajc.properties" Xreweavable="on" XpreserveAllAnnotations="on"> <include name="com/company/utility/helperAspect/HelperAspect.aj"/> <include name="com/company/utility/Helper.java"/> <!-- 新增aspectPath配置 --> <aspectPath> <pathelement location="${build.web.lib}/thirdpartylibrary-original.jar"/> </aspectPath> <classpath refid="build.classpath"> </classpath> </iajc>
仅修改第三方包中单个类的实现方法
你可以给iajc的inpath增加过滤规则,仅处理你需要修改的目标类,其他类直接原样输出,不会被重织入:
<iajc srcdir="../src" source="1.7" outjar="${build.web.lib}/thirdpartylibrary.jar" XlintFile="../src/com/company/utility/helperAspect/ajc.properties" Xreweavable="on" XpreserveAllAnnotations="on"> <!-- 仅处理inpath中的目标类,其他类直接复制 --> <inpath> <pathelement location="${build.web.lib}/thirdpartylibrary-original.jar"/> <include name="com/company/target/TargetClass.class"/> <!-- 替换为你要修改的类路径 --> </inpath> <include name="com/company/utility/helperAspect/HelperAspect.aj"/> <include name="com/company/utility/Helper.java"/> <aspectPath> <pathelement location="${build.web.lib}/thirdpartylibrary-original.jar"/> </aspectPath> <classpath refid="build.classpath"> </classpath> </iajc>
新老advice叠加无冲突的配置
如果要保证新advice叠加在原有advice之上不冲突,可做以下配置:
- 用
declare precedence指定aspect执行顺序,比如你要让原有aspect先执行,你的aspect后执行,可在你的HelperAspect.aj中增加:
declare precedence: com.company.thirdparty.*, com.company.utility.helperAspect.HelperAspect;
- 你的around advice必须调用
proceed()执行原有逻辑,不要直接替换方法实现 - 尽量缩小你的切点范围,避免和原有aspect的切点产生不必要的重叠
内容的提问来源于stack exchange,提问作者royka
相关产品推荐
相关产品推荐

